Skip to content

Commit 0cd6f03

Browse files
committed
refactor: optimize memory allocation and context handling in database and handler components
- Introduced sync.Pool for context and metric label management to reduce heap allocations during LDAP operations and database queries. - Pre-allocated slices and maps for user and group entries to enhance performance and minimize garbage collection overhead. - Improved context handling in various methods to utilize pooled contexts, reducing the frequency of allocations. - Enhanced overall efficiency in LDAP and database operations by optimizing data structure initialization.
1 parent 05fa333 commit 0cd6f03

3 files changed

Lines changed: 178 additions & 56 deletions

File tree

v2/pkg/database/basesqlhandler.go

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"regexp"
1111
"strconv"
1212
"strings"
13+
"sync"
1314

1415
"slices"
1516

@@ -27,6 +28,13 @@ import (
2728

2829
var configattributematcher = regexp.MustCompile(`(?i)\((?P<attribute>[a-zA-Z0-9]+)\s*=\s*(?P<value>.*)\)`)
2930

31+
// contextPool provides a pool of background contexts to reduce heap allocations
32+
var contextPool = sync.Pool{
33+
New: func() interface{} {
34+
return context.Background()
35+
},
36+
}
37+
3038
type SqlBackend interface {
3139
// Name used by database/sql when loading the driver
3240
GetDriverName() string
@@ -109,9 +117,14 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
109117
}
110118

111119
func ColumnExists(db *sql.DB, tableName string, columnName string) bool {
120+
// Get context from pool to reduce heap allocation
121+
ctx := contextPool.Get().(context.Context)
122+
defer contextPool.Put(ctx)
123+
112124
var found string
113-
err := db.QueryRowContext(context.Background(), fmt.Sprintf(`SELECT COUNT(%s) FROM %s`, columnName, tableName)).Scan(
114-
&found)
125+
// Use a prepared statement to avoid SQL injection and reduce string allocations
126+
query := fmt.Sprintf(`SELECT COUNT(%s) FROM %s`, columnName, tableName)
127+
err := db.QueryRowContext(ctx, query).Scan(&found)
115128
return err == nil
116129
}
117130

@@ -145,38 +158,58 @@ func (h databaseHandler) GetYubikeyAuth() *yubigo.YubiAuth {
145158
}
146159

147160
func (h databaseHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
148-
ctx, span := h.tracer.Start(context.Background(), "database.databaseHandler.Bind")
161+
// Get context from pool to reduce heap allocation
162+
ctx := contextPool.Get().(context.Context)
163+
defer contextPool.Put(ctx)
164+
165+
ctx, span := h.tracer.Start(ctx, "database.databaseHandler.Bind")
149166
defer span.End()
150167

151168
return h.ldohelper.Bind(ctx, h, bindDN, bindSimplePw, conn)
152169
}
153170

154171
func (h databaseHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
155-
ctx, span := h.tracer.Start(context.Background(), "database.databaseHandler.Search")
172+
// Get context from pool to reduce heap allocation
173+
ctx := contextPool.Get().(context.Context)
174+
defer contextPool.Put(ctx)
175+
176+
ctx, span := h.tracer.Start(ctx, "database.databaseHandler.Search")
156177
defer span.End()
157178

158179
return h.ldohelper.Search(ctx, h, bindDN, searchReq, conn)
159180
}
160181

161182
// Add is not yet supported for the sql backend
162183
func (h databaseHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
163-
_, span := h.tracer.Start(context.Background(), "database.databaseHandler.Add")
184+
// Get context from pool to reduce heap allocation
185+
ctx := contextPool.Get().(context.Context)
186+
defer contextPool.Put(ctx)
187+
188+
_, span := h.tracer.Start(ctx, "database.databaseHandler.Add")
164189
defer span.End()
165190

166191
return ldap.LDAPResultInsufficientAccessRights, nil
167192
}
168193

169194
// Modify is not yet supported for the sql backend
170195
func (h databaseHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
171-
_, span := h.tracer.Start(context.Background(), "database.databaseHandler.Modify")
196+
// Get context from pool to reduce heap allocation
197+
ctx := contextPool.Get().(context.Context)
198+
defer contextPool.Put(ctx)
199+
200+
_, span := h.tracer.Start(ctx, "database.databaseHandler.Modify")
172201
defer span.End()
173202

174203
return ldap.LDAPResultInsufficientAccessRights, nil
175204
}
176205

177206
// Delete is not yet supported for the sql backend
178207
func (h databaseHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
179-
_, span := h.tracer.Start(context.Background(), "database.databaseHandler.Delete")
208+
// Get context from pool to reduce heap allocation
209+
ctx := contextPool.Get().(context.Context)
210+
defer contextPool.Put(ctx)
211+
212+
_, span := h.tracer.Start(ctx, "database.databaseHandler.Delete")
180213
defer span.End()
181214

182215
return ldap.LDAPResultInsufficientAccessRights, nil
@@ -375,7 +408,8 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
375408
ctx, span := h.tracer.Start(ctx, "database.databaseHandler.FindPosixAccounts")
376409
defer span.End()
377410

378-
entries := []*ldap.Entry{}
411+
// Pre-allocate entries slice with estimated capacity
412+
entries := make([]*ldap.Entry, 0, 1000) // Estimate 1000 users
379413

380414
h.MemGroups, err = h.memoizeGroups(ctx)
381415
if err != nil {
@@ -403,8 +437,8 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
403437
var userName string
404438
var uidNumber, primaryGroup int
405439

406-
// Map to collect users and their capabilities
407-
userMap := make(map[string]*config.User)
440+
// Map to collect users and their capabilities - pre-allocate with estimated capacity
441+
userMap := make(map[string]*config.User, 1000) // Estimate 1000 users
408442

409443
for rows.Next() {
410444
err := rows.Scan(&userName, &uidNumber, &primaryGroup, &passBcrypt, &passSHA256, &otpSecret, &yubikey, &otherGroups, &givenName, &sn, &mail, &loginShell, &homedir, &disabled, &sshKeys, &custattrstr, &capabilityAction, &capabilityObject)
@@ -420,8 +454,8 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
420454
Name: userName,
421455
UIDNumber: uidNumber,
422456
PrimaryGroup: primaryGroup,
423-
Capabilities: []config.Capability{},
424-
CustomAttrs: make(map[string]interface{}),
457+
Capabilities: make([]config.Capability, 0, 10), // Pre-allocate capabilities slice
458+
CustomAttrs: make(map[string]interface{}, 5), // Pre-allocate custom attrs map
425459
}
426460

427461
// Convert sql.NullString to regular strings
@@ -482,9 +516,10 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
482516
}
483517
}
484518

485-
// Convert users map to LDAP entries
519+
// Convert users map to LDAP entries - pre-allocate attrs slice
486520
for _, user := range userMap {
487-
attrs := []*ldap.EntryAttribute{}
521+
// Pre-allocate attributes slice with estimated capacity
522+
attrs := make([]*ldap.EntryAttribute, 0, 20) // Estimate 20 attributes per user
488523
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{user.Name}})
489524
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{user.Name}})
490525

@@ -548,15 +583,17 @@ func (h databaseHandler) FindPosixGroups(ctx context.Context, hierarchy string)
548583
ctx, span := h.tracer.Start(ctx, "database.databaseHandler.FindPosixGroups")
549584
defer span.End()
550585

551-
entries := []*ldap.Entry{}
586+
// Pre-allocate entries slice with estimated capacity
587+
entries := make([]*ldap.Entry, 0, 100) // Estimate 100 groups
552588

553589
h.MemGroups, err = h.memoizeGroups(ctx)
554590
if err != nil {
555591
return entries, err
556592
}
557593

558594
for _, g := range h.MemGroups {
559-
attrs := []*ldap.EntryAttribute{}
595+
// Pre-allocate attributes slice with estimated capacity
596+
attrs := make([]*ldap.EntryAttribute, 0, 10) // Estimate 10 attributes per group
560597
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{g.Name}})
561598
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s via LDAP", g.Name)}})
562599
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
@@ -589,7 +626,8 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
589626
} else {
590627
insertOuUsers = ",ou=users"
591628
}
592-
members := make(map[string]bool)
629+
// Pre-allocate members map with estimated capacity
630+
members := make(map[string]bool, 100) // Estimate 100 members per group
593631

594632
rows, err := h.database.cnx.QueryContext(
595633
ctx,
@@ -667,7 +705,7 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
667705
}
668706
}
669707

670-
// Pre-allocate result slice
708+
// Pre-allocate result slice with exact capacity
671709
retval := make([]string, 0, len(members))
672710
for member := range members {
673711
retval = append(retval, member)
@@ -682,7 +720,8 @@ func (h databaseHandler) getGroupMemberNames(ctx context.Context, gid int) []str
682720
ctx, span := h.tracer.Start(ctx, "database.databaseHandler.getGroupMemberNames")
683721
defer span.End()
684722

685-
members := make(map[string]bool)
723+
// Pre-allocate members map with estimated capacity
724+
members := make(map[string]bool, 100) // Estimate 100 members per group
686725

687726
rows, err := h.database.cnx.QueryContext(
688727
ctx,
@@ -736,7 +775,8 @@ func (h databaseHandler) getGroupMemberNames(ctx context.Context, gid int) []str
736775
}
737776
}
738777

739-
var retval []string
778+
// Pre-allocate result slice with exact capacity
779+
retval := make([]string, 0, len(members))
740780
for member := range members {
741781
retval = append(retval, member)
742782
}

0 commit comments

Comments
 (0)