coocood/freecache

Add custom timer instead of time.Now() cloak time

pheepi opened this issue · 3 comments

I have my app using the cache library and several tests that check if records do not expire in a given timeout. These tests fail occasionally, because they run on a server sharing CPU with other services. I can never fix them, because the library depends on cloak time from time.Now(). The only ultimate solution here is to mock time. Do you think it would be possible to replace time.Now() with an interface representing current time? It would provide function Now(), but it could be custom and parameterized. Default implementation would still use time.Now().Unix(), but custom timer could be passed as a parameter. I have already written my own change.

By the way, it may also partly resolve issue #51.

Can you try runtime.nanotime?

// NanoTime returns the current time in nanoseconds from a monotonic clock.
//go:linkname NanoTime runtime.nanotime
func NanoTime() int64

This is one possible way to change wall time. I suppose you have an interface with one method:

type Timer interface {
	Now() uint32
}

Integer type uint32 is used, because type of expireAt is also of this type. Then you can have several types with different implementation of Now():

func (timer WallTimer) Now() uint32 {
	return uint32(time.Now().Unix())
}
func (timer MonotonicTimer) Now() uint32 {
	return uint32(runtime.nanotime())
}

It allows you to use whatever representation of time you want:

  1. Wrap online or network clock.
  2. Fake time meant for tests where you can say how much you want to proceed in every time. See github.com/jonboulle/clockwork for example. This is my expectation.
  3. Have ability to stop clock. It might be useful, for example if the cache is optimized, but the system must migrate in 24h. It allows to persist whole cache.
  4. Optimize clock for speed, e.g. like in #51.

The point of this change is that everyone may need to represent time in a different way. I would let the current behavior with wall time, but add new constructor that accepts timer interface.

@pheepi
Good idea.
Would you like to send a PR to add this interface?