Commit 1d8f62c2 authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb: Split Loader & co. interfaces from IStorage

There are situations when we want to work with, or emulate, only subset
of whole IStorage functionality, with one already established example
being Cache. For this reason split IStorage interface into finer-grained
ones. For now:

	- Loader
	- Prefetcher
	- Iterator
	- Committer
	- Notifier
parent 65c42681
...@@ -38,7 +38,7 @@ import ( ...@@ -38,7 +38,7 @@ import (
// Cache provides RAM caching layer that can be used over a storage. // Cache provides RAM caching layer that can be used over a storage.
type Cache struct { type Cache struct {
loader interface { loader interface {
StorLoader Loader
URL() string URL() string
} }
...@@ -111,12 +111,6 @@ type revCacheEntry struct { ...@@ -111,12 +111,6 @@ type revCacheEntry struct {
waitBufRef int32 waitBufRef int32
} }
// StorLoader represents loading part of a storage.
// XXX -> zodb.IStorageLoader (or zodb.Loader ?) ?
type StorLoader interface {
Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, err error)
}
// lock order: Cache.mu > oidCacheEntry // lock order: Cache.mu > oidCacheEntry
// Cache.gcMu > oidCacheEntry // Cache.gcMu > oidCacheEntry
...@@ -124,7 +118,7 @@ type StorLoader interface { ...@@ -124,7 +118,7 @@ type StorLoader interface {
// NewCache creates new cache backed up by loader. // NewCache creates new cache backed up by loader.
// //
// The cache will use not more than ~ sizeMax bytes of RAM for cached data. // The cache will use not more than ~ sizeMax bytes of RAM for cached data.
func NewCache(loader interface { StorLoader; URL() string }, sizeMax int) *Cache { func NewCache(loader interface { Loader; URL() string }, sizeMax int) *Cache {
c := &Cache{ c := &Cache{
loader: loader, loader: loader,
entryMap: make(map[Oid]*oidCacheEntry), entryMap: make(map[Oid]*oidCacheEntry),
......
...@@ -636,7 +636,7 @@ func (c *Checker) assertEq(a, b interface{}) { ...@@ -636,7 +636,7 @@ func (c *Checker) assertEq(a, b interface{}) {
// ---------------------------------------- // ----------------------------------------
// noopStorage is dummy StorLoader which for any oid/xid always returns 1-byte data. // noopStorage is dummy Loader which for any oid/xid always returns 1-byte data.
type noopStorage struct{} type noopStorage struct{}
var noopData = []byte{0} var noopData = []byte{0}
...@@ -648,15 +648,15 @@ func (s *noopStorage) Load(_ context.Context, xid Xid) (buf *mem.Buf, serial Tid ...@@ -648,15 +648,15 @@ func (s *noopStorage) Load(_ context.Context, xid Xid) (buf *mem.Buf, serial Tid
return mkbuf(noopData), 1, nil return mkbuf(noopData), 1, nil
} }
// benchLoad serially benchmarks a StorLoader - either storage directly or a cache on top of it. // benchLoad serially benchmarks a Loader - either storage directly or a cache on top of it.
// //
// oid accessed are [0, worksize) // oid accessed are [0, worksize)
func benchLoad(b *testing.B, l StorLoader, worksize int) { func benchLoad(b *testing.B, l Loader, worksize int) {
benchLoadN(b, b.N, l, worksize) benchLoadN(b, b.N, l, worksize)
} }
// worker for benchLoad, with n overridding b.N // worker for benchLoad, with n overridding b.N
func benchLoadN(b *testing.B, n int, l StorLoader, worksize int) { func benchLoadN(b *testing.B, n int, l Loader, worksize int) {
ctx := context.Background() ctx := context.Background()
xid := Xid{At: 1, Oid: 0} xid := Xid{At: 1, Oid: 0}
...@@ -723,7 +723,7 @@ func BenchmarkCacheHit(b *testing.B) { ...@@ -723,7 +723,7 @@ func BenchmarkCacheHit(b *testing.B) {
// ---- parallel benchmarks (many requests to 1 cache) ---- // ---- parallel benchmarks (many requests to 1 cache) ----
// benchLoadPar is like benchLoad but issues loads in parallel // benchLoadPar is like benchLoad but issues loads in parallel
func benchLoadPar(b *testing.B, l StorLoader, worksize int) { func benchLoadPar(b *testing.B, l Loader, worksize int) {
ctx := context.Background() ctx := context.Background()
np := runtime.GOMAXPROCS(0) np := runtime.GOMAXPROCS(0)
p := uint64(0) p := uint64(0)
...@@ -776,7 +776,7 @@ func BenchmarkCacheHitPar(b *testing.B) { ...@@ -776,7 +776,7 @@ func BenchmarkCacheHitPar(b *testing.B) {
// XXX this benchmark part will probably go away // XXX this benchmark part will probably go away
// benchLoadProc is like benchLoad but works with PB, not B // benchLoadProc is like benchLoad but works with PB, not B
func benchLoadProc(pb *testing.PB, l StorLoader, worksize int) error { func benchLoadProc(pb *testing.PB, l Loader, worksize int) error {
ctx := context.Background() ctx := context.Background()
xid := Xid{At: 1, Oid: 0} xid := Xid{At: 1, Oid: 0}
......
...@@ -212,6 +212,11 @@ func (e *OpError) Cause() error { ...@@ -212,6 +212,11 @@ func (e *OpError) Cause() error {
type IStorage interface { type IStorage interface {
IStorageDriver IStorageDriver
Prefetcher
}
// Prefetcher provides functionality to prefetch objects.
type Prefetcher interface {
// Prefetch prefetches object addressed by xid. // Prefetch prefetches object addressed by xid.
// //
// If data is not yet in cache loading for it is started in the background. // If data is not yet in cache loading for it is started in the background.
...@@ -236,6 +241,12 @@ type IStorageDriver interface { ...@@ -236,6 +241,12 @@ type IStorageDriver interface {
// If no transactions have been committed yet, LastTid returns 0. // If no transactions have been committed yet, LastTid returns 0.
LastTid(ctx context.Context) (Tid, error) LastTid(ctx context.Context) (Tid, error)
Loader
Iterator
}
// Loader provides functionality to load objects.
type Loader interface {
// Load loads object data addressed by xid from database. // Load loads object data addressed by xid from database.
// //
// Returned are: // Returned are:
...@@ -277,7 +288,10 @@ type IStorageDriver interface { ...@@ -277,7 +288,10 @@ type IStorageDriver interface {
// cache without serial_next returned from Load. For this reason in ZODB/go // cache without serial_next returned from Load. For this reason in ZODB/go
// Load specification comes without specifying serial_next return. // Load specification comes without specifying serial_next return.
Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, err error) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, err error)
}
// Committer provides functionality to commit transactions.
type Committer interface {
// TODO: write mode // TODO: write mode
// Store(ctx, oid Oid, serial Tid, data []byte, txn ITransaction) error // Store(ctx, oid Oid, serial Tid, data []byte, txn ITransaction) error
...@@ -287,12 +301,19 @@ type IStorageDriver interface { ...@@ -287,12 +301,19 @@ type IStorageDriver interface {
// TpcVote(txn) // TpcVote(txn)
// TpcFinish(txn, callback) // TpcFinish(txn, callback)
// TpcAbort(txn) // TpcAbort(txn)
}
// Notifier allows to be notified of database changes made by other clients.
type Notifier interface {
// TODO: invalidation channel (notify about changes made to DB not by us from outside) // TODO: invalidation channel (notify about changes made to DB not by us from outside)
}
// TODO: History(ctx, oid, size=1) // TODO: History(ctx, oid, size=1)
// Iterator provides functionality to iterate through storage transactions sequentially.
type Iterator interface {
// Iterate creates iterator to iterate storage in [tidMin, tidMax] range. // Iterate creates iterator to iterate storage in [tidMin, tidMax] range.
// //
// Iterate does not return any error. If there was error when setting // Iterate does not return any error. If there was error when setting
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment