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  }