You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2022/03/25 19:32:41 UTC

[GitHub] [trafficcontrol] srijeet0406 commented on a change in pull request #6671: Add TO in-memory User cache option to improve performance

srijeet0406 commented on a change in pull request #6671:
URL: https://github.com/apache/trafficcontrol/pull/6671#discussion_r835555694



##########
File path: traffic_ops/traffic_ops_golang/auth/usercache.go
##########
@@ -0,0 +1,208 @@
+package auth
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"context"
+	"database/sql"
+	"errors"
+	"sync"
+	"time"
+
+	"github.com/apache/trafficcontrol/lib/go-log"
+
+	"github.com/lib/pq"
+)
+
+const (
+	getUsersQuery = `
+		SELECT
+			u.id,
+			u.local_passwd,
+			u.role,
+			u.tenant_id,
+			u.token,
+			u.ucdn,
+			u.username
+		FROM
+			tm_user AS u
+	`
+	getRolesQuery = `
+		SELECT
+			ARRAY(SELECT rc.cap_name FROM role_capability AS rc WHERE rc.role_id=r.id) AS capabilities,
+			r.id as role,
+			r.name as role_name,
+			r.priv_level
+		FROM role r
+	`
+)
+
+type user struct {
+	CurrentUser
+	LocalPasswd *string
+	Token       *string
+}
+
+type role struct {
+	Capabilities pq.StringArray
+	ID           int
+	Name         string
+	PrivLevel    int
+}
+
+type users struct {
+	userMap          map[string]user
+	usernamesByToken map[string]string
+	*sync.RWMutex
+	initialized bool
+	enabled     bool // note: enabled is only written to once at startup, before serving requests, so it doesn't need synchronized access
+}
+
+var usersCache = users{RWMutex: &sync.RWMutex{}}
+
+func usersCacheIsEnabled() bool {
+	if usersCache.enabled {
+		usersCache.RLock()
+		defer usersCache.RUnlock()
+		return usersCache.initialized
+	}
+	return false
+}
+
+// getUserFromCache returns the user with the given username and a boolean indicating whether the user exists.
+func getUserFromCache(username string) (user, bool) {
+	usersCache.RLock()
+	defer usersCache.RUnlock()
+	u, exists := usersCache.userMap[username]
+	return u, exists
+}
+
+// getUserNameFromCacheByToken returns the username with the given token or an empty string if not found.
+func getUserNameFromCacheByToken(token string) string {

Review comment:
       That way we don't have to check it everywhere this function gets called.

##########
File path: traffic_ops/traffic_ops_golang/auth/authorize.go
##########
@@ -197,15 +217,26 @@ func GetUserUcdn(form PasswordForm, db *sqlx.DB, ctx context.Context) (string, e
 
 func CheckLocalUserPassword(form PasswordForm, db *sqlx.DB, ctx context.Context) (bool, error, error) {
 	var hashedPassword string
-
-	err := db.GetContext(ctx, &hashedPassword, "SELECT local_passwd FROM tm_user WHERE username=$1", form.Username)
-	if err != nil {
-		if err == context.DeadlineExceeded || err == context.Canceled {
-			return false, nil, err
+	if usersCacheIsEnabled() {
+		u, exists := getUserFromCache(form.Username)
+		if !exists {
+			return false, fmt.Errorf("user '%s' not found in cache", form.Username), nil
+		}
+		if u.LocalPasswd == nil {
+			return false, nil, nil

Review comment:
       Should we return some kind of an error here, saying that the localpswd was `nil`?

##########
File path: traffic_ops/traffic_ops_golang/auth/usercache.go
##########
@@ -0,0 +1,208 @@
+package auth
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"context"
+	"database/sql"
+	"errors"
+	"sync"
+	"time"
+
+	"github.com/apache/trafficcontrol/lib/go-log"
+
+	"github.com/lib/pq"
+)
+
+const (
+	getUsersQuery = `
+		SELECT
+			u.id,
+			u.local_passwd,
+			u.role,
+			u.tenant_id,
+			u.token,
+			u.ucdn,
+			u.username
+		FROM
+			tm_user AS u
+	`
+	getRolesQuery = `
+		SELECT
+			ARRAY(SELECT rc.cap_name FROM role_capability AS rc WHERE rc.role_id=r.id) AS capabilities,
+			r.id as role,
+			r.name as role_name,
+			r.priv_level
+		FROM role r
+	`
+)
+
+type user struct {
+	CurrentUser
+	LocalPasswd *string
+	Token       *string
+}
+
+type role struct {
+	Capabilities pq.StringArray
+	ID           int
+	Name         string
+	PrivLevel    int
+}
+
+type users struct {
+	userMap          map[string]user
+	usernamesByToken map[string]string
+	*sync.RWMutex
+	initialized bool
+	enabled     bool // note: enabled is only written to once at startup, before serving requests, so it doesn't need synchronized access
+}
+
+var usersCache = users{RWMutex: &sync.RWMutex{}}
+
+func usersCacheIsEnabled() bool {
+	if usersCache.enabled {
+		usersCache.RLock()
+		defer usersCache.RUnlock()
+		return usersCache.initialized
+	}
+	return false
+}
+
+// getUserFromCache returns the user with the given username and a boolean indicating whether the user exists.
+func getUserFromCache(username string) (user, bool) {
+	usersCache.RLock()
+	defer usersCache.RUnlock()
+	u, exists := usersCache.userMap[username]
+	return u, exists
+}
+
+// getUserNameFromCacheByToken returns the username with the given token or an empty string if not found.
+func getUserNameFromCacheByToken(token string) string {

Review comment:
       just for uniformity sake, does it make sense to return a boolean here to denote whether or not the username was found, and whether or not it was = `""`?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@trafficcontrol.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org