Merge pull request #103 from bluesuncorp/v5-development
Implement native go sync.Pool
Dean Karn
8 years ago
6 | 6 | on_failure: always |
7 | 7 | |
8 | 8 | go: |
9 | - 1.2 | |
10 | 9 | - 1.3 |
11 | 10 | - 1.4 |
12 | 11 | - tip |
13 | ||
14 | before_install: | |
15 | - go get github.com/axw/gocov/gocov | |
12 | ||
13 | script: | |
14 | - go get golang.org/x/tools/cmd/cover | |
16 | 15 | - go get github.com/mattn/goveralls |
17 | - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi | |
18 | script: | |
19 | - $HOME/gopath/bin/goveralls -service=travis-ci | |
16 | - go test -v -covermode=count -coverprofile=cover.out | |
17 | ||
18 | after_success: | |
19 | - goveralls -coverprofile=cover.out -service=travis-ci -repotoken I6M8FiXZzErImgwMotJ7fwFlHOX8Hqdq1⏎ |
23 | 23 | } |
24 | 24 | } |
25 | 25 | |
26 | // func BenchmarkTemplateParallelSimple(b *testing.B) { | |
26 | func BenchmarkTemplateParallelSimple(b *testing.B) { | |
27 | 27 | |
28 | // type Foo struct { | |
29 | // StringValue string `validate:"min=5,max=10"` | |
30 | // IntValue int `validate:"min=5,max=10"` | |
31 | // } | |
28 | type Foo struct { | |
29 | StringValue string `validate:"min=5,max=10"` | |
30 | IntValue int `validate:"min=5,max=10"` | |
31 | } | |
32 | 32 | |
33 | // validFoo := &Foo{StringValue: "Foobar", IntValue: 7} | |
34 | // invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} | |
33 | validFoo := &Foo{StringValue: "Foobar", IntValue: 7} | |
34 | invalidFoo := &Foo{StringValue: "Fo", IntValue: 3} | |
35 | 35 | |
36 | // b.RunParallel(func(pb *testing.PB) { | |
37 | // for pb.Next() { | |
38 | // validate.Struct(validFoo) | |
39 | // validate.Struct(invalidFoo) | |
40 | // } | |
41 | // }) | |
42 | // } | |
36 | b.RunParallel(func(pb *testing.PB) { | |
37 | for pb.Next() { | |
38 | validate.Struct(validFoo) | |
39 | validate.Struct(invalidFoo) | |
40 | } | |
41 | }) | |
42 | } | |
43 | 43 | |
44 | 44 | func BenchmarkValidateStructLarge(b *testing.B) { |
45 | 45 | |
100 | 100 | } |
101 | 101 | } |
102 | 102 | |
103 | // func BenchmarkTemplateParallelLarge(b *testing.B) { | |
103 | func BenchmarkTemplateParallelLarge(b *testing.B) { | |
104 | 104 | |
105 | // tFail := &TestString{ | |
106 | // Required: "", | |
107 | // Len: "", | |
108 | // Min: "", | |
109 | // Max: "12345678901", | |
110 | // MinMax: "", | |
111 | // Lt: "0123456789", | |
112 | // Lte: "01234567890", | |
113 | // Gt: "1", | |
114 | // Gte: "1", | |
115 | // OmitEmpty: "12345678901", | |
116 | // Sub: &SubTest{ | |
117 | // Test: "", | |
118 | // }, | |
119 | // Anonymous: struct { | |
120 | // A string `validate:"required"` | |
121 | // }{ | |
122 | // A: "", | |
123 | // }, | |
124 | // Iface: &Impl{ | |
125 | // F: "12", | |
126 | // }, | |
127 | // } | |
105 | tFail := &TestString{ | |
106 | Required: "", | |
107 | Len: "", | |
108 | Min: "", | |
109 | Max: "12345678901", | |
110 | MinMax: "", | |
111 | Lt: "0123456789", | |
112 | Lte: "01234567890", | |
113 | Gt: "1", | |
114 | Gte: "1", | |
115 | OmitEmpty: "12345678901", | |
116 | Sub: &SubTest{ | |
117 | Test: "", | |
118 | }, | |
119 | Anonymous: struct { | |
120 | A string `validate:"required"` | |
121 | }{ | |
122 | A: "", | |
123 | }, | |
124 | Iface: &Impl{ | |
125 | F: "12", | |
126 | }, | |
127 | } | |
128 | 128 | |
129 | // tSuccess := &TestString{ | |
130 | // Required: "Required", | |
131 | // Len: "length==10", | |
132 | // Min: "min=1", | |
133 | // Max: "1234567890", | |
134 | // MinMax: "12345", | |
135 | // Lt: "012345678", | |
136 | // Lte: "0123456789", | |
137 | // Gt: "01234567890", | |
138 | // Gte: "0123456789", | |
139 | // OmitEmpty: "", | |
140 | // Sub: &SubTest{ | |
141 | // Test: "1", | |
142 | // }, | |
143 | // SubIgnore: &SubTest{ | |
144 | // Test: "", | |
145 | // }, | |
146 | // Anonymous: struct { | |
147 | // A string `validate:"required"` | |
148 | // }{ | |
149 | // A: "1", | |
150 | // }, | |
151 | // Iface: &Impl{ | |
152 | // F: "123", | |
153 | // }, | |
154 | // } | |
129 | tSuccess := &TestString{ | |
130 | Required: "Required", | |
131 | Len: "length==10", | |
132 | Min: "min=1", | |
133 | Max: "1234567890", | |
134 | MinMax: "12345", | |
135 | Lt: "012345678", | |
136 | Lte: "0123456789", | |
137 | Gt: "01234567890", | |
138 | Gte: "0123456789", | |
139 | OmitEmpty: "", | |
140 | Sub: &SubTest{ | |
141 | Test: "1", | |
142 | }, | |
143 | SubIgnore: &SubTest{ | |
144 | Test: "", | |
145 | }, | |
146 | Anonymous: struct { | |
147 | A string `validate:"required"` | |
148 | }{ | |
149 | A: "1", | |
150 | }, | |
151 | Iface: &Impl{ | |
152 | F: "123", | |
153 | }, | |
154 | } | |
155 | 155 | |
156 | // b.RunParallel(func(pb *testing.PB) { | |
157 | // for pb.Next() { | |
158 | // validate.Struct(tSuccess) | |
159 | // validate.Struct(tFail) | |
160 | // } | |
161 | // }) | |
162 | // } | |
156 | b.RunParallel(func(pb *testing.PB) { | |
157 | for pb.Next() { | |
158 | validate.Struct(tSuccess) | |
159 | validate.Struct(tFail) | |
160 | } | |
161 | }) | |
162 | } |
36 | 36 | mapIndexFieldName = "%s[%v]" |
37 | 37 | ) |
38 | 38 | |
39 | var structPool *pool | |
40 | ||
41 | // Pool holds a channelStructErrors. | |
42 | type pool struct { | |
43 | pool chan *StructErrors | |
44 | } | |
45 | ||
46 | // NewPool creates a new pool of Clients. | |
47 | func newPool(max int) *pool { | |
48 | return &pool{ | |
49 | pool: make(chan *StructErrors, max), | |
50 | } | |
51 | } | |
52 | ||
53 | // Borrow a StructErrors from the pool. | |
54 | func (p *pool) Borrow() *StructErrors { | |
55 | var c *StructErrors | |
56 | ||
57 | select { | |
58 | case c = <-p.pool: | |
59 | default: | |
60 | c = &StructErrors{ | |
61 | Errors: map[string]*FieldError{}, | |
62 | StructErrors: map[string]*StructErrors{}, | |
63 | } | |
64 | } | |
65 | ||
66 | return c | |
67 | } | |
68 | ||
69 | // Return returns a StructErrors to the pool. | |
70 | func (p *pool) Return(c *StructErrors) { | |
71 | ||
72 | select { | |
73 | case p.pool <- c: | |
74 | default: | |
75 | // let it go, let it go... | |
39 | var structPool *sync.Pool | |
40 | ||
41 | // returns new *StructErrors to the pool | |
42 | func newStructErrors() interface{} { | |
43 | return &StructErrors{ | |
44 | Errors: map[string]*FieldError{}, | |
45 | StructErrors: map[string]*StructErrors{}, | |
76 | 46 | } |
77 | 47 | } |
78 | 48 | |
356 | 326 | // New creates a new Validate instance for use. |
357 | 327 | func New(tagName string, funcs map[string]Func) *Validate { |
358 | 328 | |
359 | structPool = newPool(10) | |
329 | structPool = &sync.Pool{New: newStructErrors} | |
360 | 330 | |
361 | 331 | return &Validate{ |
362 | 332 | tagName: tagName, |
376 | 346 | // nearly all cases. only increase if you have a deeply nested struct structure. |
377 | 347 | // NOTE: this method is not thread-safe |
378 | 348 | // NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed |
379 | // and the max pool size will be passed into the New function | |
380 | 349 | func (v *Validate) SetMaxStructPoolSize(max int) { |
381 | structPool = newPool(max) | |
350 | structPool = &sync.Pool{New: newStructErrors} | |
382 | 351 | } |
383 | 352 | |
384 | 353 | // AddFunction adds a validation Func to a Validate's map of validators denoted by the key |
439 | 408 | cs = &cachedStruct{name: structName, children: numFields} |
440 | 409 | } |
441 | 410 | |
442 | validationErrors := structPool.Borrow() | |
411 | validationErrors := structPool.Get().(*StructErrors) | |
443 | 412 | validationErrors.Struct = structName |
444 | 413 | |
445 | 414 | for i := 0; i < numFields; i++ { |
616 | 585 | structCache.Set(structType, cs) |
617 | 586 | |
618 | 587 | if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 { |
619 | structPool.Return(validationErrors) | |
588 | structPool.Put(validationErrors) | |
620 | 589 | return nil |
621 | 590 | } |
622 | 591 |