Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Memory ¶
Memory implements an in-memory key/value store with integer autoincrement keys and delayed writes. Internally uses a map for data storage instead of a slice for different reasons:
- Ease of implementation (deterministic index)
- Memory allocation time is predictable
- Future proofing (deletes)
Slices and channels would be the straight forward, solution but implementation has a lot of caveats:
- When waiting time.Sleep inside goroutines is non deterministic, scheduler might finish a routine faster and thus append in the wrong order. This can be solved by tracking the size of the slice and grow on demand, runtime should be responsible for this, not the developer.
- Working with buffered channels means, ideally, the write to the channel is done inside a select clause with a default statement to avoid blocking, I would personally use this approach if latency was unpredictable or we want to have a limit on pending writes, but we have fixed delay and the sync.WaitGroup can easily be customized to achieve a similar limiter functionality.
- If deletes become a requirement, slices just fall way behind in terms of performance due to memory management.
The benefits of slices do not outweight the added complexity go maps have O(1) amortized complexity for insert and lookups on finite space domains (integer), making them performant.
func NewMemory ¶
NewMemory creates a new store with 'delay' writes. It is useful to allow the caller to setup the delay, specially for testing as we avoid mocking.
func (*Memory) Close ¶
Close blocks until all pending write operations are done Useful if data would be persisted, otherwise just a nice "to have" in case other implementations are done.