add caching pool of StructErrors to reuse objects, reduce garbage collection and reduce memory allocations

for #56
pull/68/head
joeybloggs 9 years ago
parent 678d778cba
commit fcbf6b65e4
  1. 63
      validator.go

@ -31,6 +31,48 @@ const (
structErrMsg = "Struct:%s\n"
)
var structPool *pool
// Pool holds a channelStructErrors.
type pool struct {
pool chan *StructErrors
}
// NewPool creates a new pool of Clients.
func newPool(max int) *pool {
return &pool{
pool: make(chan *StructErrors, max),
}
}
// Borrow a StructErrors from the pool.
func (p *pool) Borrow() *StructErrors {
var c *StructErrors
select {
case c = <-p.pool:
default:
c = &StructErrors{
Errors: map[string]*FieldError{},
StructErrors: map[string]*StructErrors{},
}
}
return c
}
// Return returns a StructErrors to the pool.
func (p *pool) Return(c *StructErrors) {
// c.Struct = ""
select {
case p.pool <- c:
default:
// let it go, let it go...
}
}
type cachedTags struct {
keyVals [][]string
isOrVal bool
@ -188,6 +230,9 @@ type Validate struct {
// New creates a new Validate instance for use.
func New(tagName string, funcs map[string]Func) *Validate {
structPool = newPool(10)
return &Validate{
tagName: tagName,
validationFuncs: funcs,
@ -201,6 +246,16 @@ func (v *Validate) SetTag(tagName string) {
v.tagName = tagName
}
// SetStructPoolMax sets the struct pools max size. this may be usefull for fine grained
// performance tuning towards your application, however, the default should be fine for
// nearly all cases. only increase if you have a deeply nested struct structure.
// NOTE: this method is not thread-safe
// NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed
// and the max pool size will be passed into the New function
func (v *Validate) SetMaxStructPoolSize(max int) {
structPool = newPool(max)
}
// AddFunction adds a validation Func to a Validate's map of validators denoted by the key
// NOTE: if the key already exists, it will get replaced.
// NOTE: this method is not thread-safe
@ -260,11 +315,8 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
structCache.Set(structType, cs)
}
validationErrors := &StructErrors{
Struct: structName,
Errors: map[string]*FieldError{},
StructErrors: map[string]*StructErrors{},
}
validationErrors := structPool.Borrow()
validationErrors.Struct = structName
for i := 0; i < numFields; i++ {
@ -360,6 +412,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
}
if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 {
structPool.Return(validationErrors)
return nil
}

Loading…
Cancel
Save