Skip to content

Commit fcbf6b6

Browse files
joeybloggsjoeybloggs
authored andcommitted
add caching pool of StructErrors to reuse objects, reduce garbage collection and reduce memory allocations
for #56
1 parent 678d778 commit fcbf6b6

File tree

1 file changed

+58
-5
lines changed

1 file changed

+58
-5
lines changed

validator.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,48 @@ const (
3131
structErrMsg = "Struct:%s\n"
3232
)
3333

34+
var structPool *pool
35+
36+
// Pool holds a channelStructErrors.
37+
type pool struct {
38+
pool chan *StructErrors
39+
}
40+
41+
// NewPool creates a new pool of Clients.
42+
func newPool(max int) *pool {
43+
return &pool{
44+
pool: make(chan *StructErrors, max),
45+
}
46+
}
47+
48+
// Borrow a StructErrors from the pool.
49+
func (p *pool) Borrow() *StructErrors {
50+
var c *StructErrors
51+
52+
select {
53+
case c = <-p.pool:
54+
default:
55+
c = &StructErrors{
56+
Errors: map[string]*FieldError{},
57+
StructErrors: map[string]*StructErrors{},
58+
}
59+
}
60+
61+
return c
62+
}
63+
64+
// Return returns a StructErrors to the pool.
65+
func (p *pool) Return(c *StructErrors) {
66+
67+
// c.Struct = ""
68+
69+
select {
70+
case p.pool <- c:
71+
default:
72+
// let it go, let it go...
73+
}
74+
}
75+
3476
type cachedTags struct {
3577
keyVals [][]string
3678
isOrVal bool
@@ -188,6 +230,9 @@ type Validate struct {
188230

189231
// New creates a new Validate instance for use.
190232
func New(tagName string, funcs map[string]Func) *Validate {
233+
234+
structPool = newPool(10)
235+
191236
return &Validate{
192237
tagName: tagName,
193238
validationFuncs: funcs,
@@ -201,6 +246,16 @@ func (v *Validate) SetTag(tagName string) {
201246
v.tagName = tagName
202247
}
203248

249+
// SetStructPoolMax sets the struct pools max size. this may be usefull for fine grained
250+
// performance tuning towards your application, however, the default should be fine for
251+
// nearly all cases. only increase if you have a deeply nested struct structure.
252+
// NOTE: this method is not thread-safe
253+
// NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed
254+
// and the max pool size will be passed into the New function
255+
func (v *Validate) SetMaxStructPoolSize(max int) {
256+
structPool = newPool(max)
257+
}
258+
204259
// AddFunction adds a validation Func to a Validate's map of validators denoted by the key
205260
// NOTE: if the key already exists, it will get replaced.
206261
// NOTE: this method is not thread-safe
@@ -260,11 +315,8 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
260315
structCache.Set(structType, cs)
261316
}
262317

263-
validationErrors := &StructErrors{
264-
Struct: structName,
265-
Errors: map[string]*FieldError{},
266-
StructErrors: map[string]*StructErrors{},
267-
}
318+
validationErrors := structPool.Borrow()
319+
validationErrors.Struct = structName
268320

269321
for i := 0; i < numFields; i++ {
270322

@@ -360,6 +412,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
360412
}
361413

362414
if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 {
415+
structPool.Return(validationErrors)
363416
return nil
364417
}
365418

0 commit comments

Comments
 (0)