Skip to content

Commit

Permalink
Add custom timer interface (coocood#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
pheepi committed Jan 14, 2020
1 parent cf06d5f commit d8164ec
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 7 deletions.
10 changes: 9 additions & 1 deletion cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,20 @@ func hashFunc(data []byte) uint64 {
// `debug.SetGCPercent()`, set it to a much smaller value
// to limit the memory consumption and GC pause time.
func NewCache(size int) (cache *Cache) {
return NewCacheCustomTimer(size, defaultTimer{})
}

// NewCacheCustomTimer returns new cache with custom timer.
func NewCacheCustomTimer(size int, timer Timer) (cache *Cache) {
if size < minBufSize {
size = minBufSize
}
if timer == nil {
timer = defaultTimer{}
}
cache = new(Cache)
for i := 0; i < segmentCount; i++ {
cache.segments[i] = newSegment(size/segmentCount, i)
cache.segments[i] = newSegment(size/segmentCount, i, timer)
}
return
}
Expand Down
3 changes: 1 addition & 2 deletions iterator.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package freecache

import (
"time"
"unsafe"
)

Expand Down Expand Up @@ -56,7 +55,7 @@ func (it *Iterator) nextForSlot(seg *segment, slotId int) *Entry {
for it.entryIdx < len(slot) {
ptr := slot[it.entryIdx]
it.entryIdx++
now := uint32(time.Now().Unix())
now := seg.timer.Now()
var hdrBuf [ENTRY_HDR_SIZE]byte
seg.rb.ReadAt(hdrBuf[:], ptr.offset)
hdr := (*entryHdr)(unsafe.Pointer(&hdrBuf[0]))
Expand Down
22 changes: 18 additions & 4 deletions segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ var ErrLargeKey = errors.New("The key is larger than 65535")
var ErrLargeEntry = errors.New("The entry size is larger than 1/1024 of cache size")
var ErrNotFound = errors.New("Entry not found")

// timer holds representation of current time.
type Timer interface {
// Give current time in nanosecond precision
Now() uint32
}

// entry pointer struct points to an entry in ring buffer
type entryPtr struct {
offset int64 // entry offset in ring buffer
Expand Down Expand Up @@ -46,6 +52,7 @@ type segment struct {
entryCount int64
totalCount int64 // number of entries in ring buffer, including deleted entries.
totalTime int64 // used to calculate least recent used entry.
timer Timer // Timer giving current time
totalEvacuate int64 // used for debug
totalExpired int64 // used for debug
overwrites int64 // used for debug
Expand All @@ -55,9 +62,16 @@ type segment struct {
slotsData []entryPtr // shared by all 256 slots
}

func newSegment(bufSize int, segId int) (seg segment) {
type defaultTimer struct{}

func (timer defaultTimer) Now() uint32 {
return uint32(time.Now().Unix())
}

func newSegment(bufSize int, segId int, timer Timer) (seg segment) {
seg.rb = NewRingBuf(bufSize, 0)
seg.segId = segId
seg.timer = timer
seg.vacuumLen = int64(bufSize)
seg.slotCap = 1
seg.slotsData = make([]entryPtr, 256*seg.slotCap)
Expand All @@ -73,7 +87,7 @@ func (seg *segment) set(key, value []byte, hashVal uint64, expireSeconds int) (e
// Do not accept large entry.
return ErrLargeEntry
}
now := uint32(time.Now().Unix())
now := seg.timer.Now()
expireAt := uint32(0)
if expireSeconds > 0 {
expireAt = now + uint32(expireSeconds)
Expand Down Expand Up @@ -207,7 +221,7 @@ func (seg *segment) get(key, buf []byte, hashVal uint64, peek bool) (value []byt
seg.rb.ReadAt(hdrBuf[:], ptr.offset)
hdr := (*entryHdr)(unsafe.Pointer(&hdrBuf[0]))
if !peek {
now := uint32(time.Now().Unix())
now := seg.timer.Now()
expireAt = hdr.expireAt

if hdr.expireAt != 0 && hdr.expireAt <= now {
Expand Down Expand Up @@ -256,7 +270,7 @@ func (seg *segment) ttl(key []byte, hashVal uint64) (timeLeft uint32, err error)
return
}
ptr := &slot[idx]
now := uint32(time.Now().Unix())
now := seg.timer.Now()

var hdrBuf [ENTRY_HDR_SIZE]byte
seg.rb.ReadAt(hdrBuf[:], ptr.offset)
Expand Down

0 comments on commit d8164ec

Please sign in to comment.