github.com/maypok86/otter@v1.2.1/internal/unixtime/unixtime.go (about) 1 // Copyright (c) 2023 Alexey Mayshev. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package unixtime 16 17 import ( 18 "sync" 19 "sync/atomic" 20 "time" 21 ) 22 23 var ( 24 // We need this package because time.Now() is slower, allocates memory, 25 // and we don't need a more precise time for the expiry time (and most other operations). 26 now uint32 27 startTime int64 28 29 mutex sync.Mutex 30 countInstance int 31 done chan struct{} 32 ) 33 34 func startTimer() { 35 done = make(chan struct{}) 36 atomic.StoreInt64(&startTime, time.Now().Unix()) 37 atomic.StoreUint32(&now, uint32(0)) 38 39 go func() { 40 ticker := time.NewTicker(time.Second) 41 defer ticker.Stop() 42 for { 43 select { 44 case t := <-ticker.C: 45 atomic.StoreUint32(&now, uint32(t.Unix()-StartTime())) 46 case <-done: 47 return 48 } 49 } 50 }() 51 } 52 53 // Start should be called when the cache instance is created to initialize the timer. 54 func Start() { 55 mutex.Lock() 56 defer mutex.Unlock() 57 58 if countInstance == 0 { 59 startTimer() 60 } 61 62 countInstance++ 63 } 64 65 // Stop should be called when closing and stopping the cache instance to stop the timer. 66 func Stop() { 67 mutex.Lock() 68 defer mutex.Unlock() 69 70 countInstance-- 71 if countInstance == 0 { 72 done <- struct{}{} 73 close(done) 74 } 75 } 76 77 // Now returns time as a Unix time, the number of seconds elapsed since program start. 78 func Now() uint32 { 79 return atomic.LoadUint32(&now) 80 } 81 82 // SetNow sets the current time. 83 // 84 // NOTE: use only for testing and debugging. 85 func SetNow(t uint32) { 86 atomic.StoreUint32(&now, t) 87 } 88 89 // StartTime returns the start time of the program. 90 func StartTime() int64 { 91 return atomic.LoadInt64(&startTime) 92 }