├── .gitignore ├── LICENSE ├── README.md ├── once.go └── once_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mat Ryer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # resync 2 | 3 | `sync.Once` with `Reset()` 4 | 5 | * See [sync.Once](http://golang.org/pkg/sync/#Once) 6 | 7 | Rather than adding this project as a dependency, consider [dropping](https://github.com/matryer/drop) this file into your project. 8 | 9 | ## Example 10 | 11 | The following example examines how `resync.Once` could be used in a HTTP server situation. 12 | 13 | ```go 14 | // use it just like sync.Once 15 | var once resync.Once 16 | 17 | // handle a web request 18 | func handleRequest(w http.ResponseWriter, r *http.Request) { 19 | once.Do(func(){ 20 | // load templates or something 21 | }) 22 | // TODO: respond 23 | } 24 | 25 | // handle some request that indicates things have changed 26 | func handleResetRequest(w http.ResponseWriter, r *http.Request) { 27 | once.Reset() // call Reset to cause initialisation to happen again above 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /once.go: -------------------------------------------------------------------------------- 1 | package resync 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | // Once is an object that will perform exactly one action 9 | // until Reset is called. 10 | // See http://golang.org/pkg/sync/#Once 11 | type Once struct { 12 | m sync.Mutex 13 | done uint32 14 | } 15 | 16 | // Do simulates sync.Once.Do by executing the specified function 17 | // only once, until Reset is called. 18 | // See http://golang.org/pkg/sync/#Once 19 | func (o *Once) Do(f func()) { 20 | if atomic.LoadUint32(&o.done) == 1 { 21 | return 22 | } 23 | // Slow-path. 24 | o.m.Lock() 25 | defer o.m.Unlock() 26 | if o.done == 0 { 27 | defer atomic.StoreUint32(&o.done, 1) 28 | f() 29 | } 30 | } 31 | 32 | // Reset indicates that the next call to Do should actually be called 33 | // once again. 34 | func (o *Once) Reset() { 35 | o.m.Lock() 36 | defer o.m.Unlock() 37 | atomic.StoreUint32(&o.done, 0) 38 | } 39 | -------------------------------------------------------------------------------- /once_test.go: -------------------------------------------------------------------------------- 1 | package resync_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cheekybits/is" 7 | "github.com/matryer/resync" 8 | ) 9 | 10 | func TestOnceReset(t *testing.T) { 11 | is := is.New(t) 12 | var calls int 13 | var c resync.Once 14 | c.Do(func() { 15 | calls++ 16 | }) 17 | c.Do(func() { 18 | calls++ 19 | }) 20 | c.Do(func() { 21 | calls++ 22 | }) 23 | is.Equal(calls, 1) 24 | c.Reset() 25 | c.Do(func() { 26 | calls++ 27 | }) 28 | c.Do(func() { 29 | calls++ 30 | }) 31 | c.Do(func() { 32 | calls++ 33 | }) 34 | is.Equal(calls, 2) 35 | } 36 | --------------------------------------------------------------------------------