CacheWrap() -> CacheDB() CacheDB

This commit is contained in:
Jae Kwon 2017-11-11 17:33:41 -05:00
parent 8481c49c82
commit 56e51bc113
7 changed files with 49 additions and 43 deletions

View File

@ -120,7 +120,7 @@ func (db *CLevelDB) Stats() map[string]string {
return stats return stats
} }
func (db *CLevelDB) CacheWrap() interface{} { func (db *CLevelDB) CacheDB() CacheDB {
return NewCacheDB(db, db.GetWriteLockVersion()) return NewCacheDB(db, db.GetWriteLockVersion())
} }

View File

@ -16,8 +16,8 @@ type cDBValue struct {
dirty bool dirty bool
} }
// CacheDB wraps an in-memory cache around an underlying DB. // cacheDB wraps an in-memory cache around an underlying DB.
type CacheDB struct { type cacheDB struct {
mtx sync.Mutex mtx sync.Mutex
cache map[string]cDBValue cache map[string]cDBValue
parent DB parent DB
@ -27,13 +27,14 @@ type CacheDB struct {
} }
// Needed by MultiStore.CacheWrap(). // Needed by MultiStore.CacheWrap().
var _ atomicSetDeleter = (*CacheDB)(nil) var _ atomicSetDeleter = (*cacheDB)(nil)
var _ CacheDB = (*cacheDB)(nil)
// Users should typically not be required to call NewCacheDB directly, as the // Users should typically not be required to call NewCacheDB directly, as the
// DB implementations here provide a .CacheWrap() function already. // DB implementations here provide a .CacheDB() function already.
// `lockVersion` is typically provided by parent.GetWriteLockVersion(). // `lockVersion` is typically provided by parent.GetWriteLockVersion().
func NewCacheDB(parent DB, lockVersion interface{}) *CacheDB { func NewCacheDB(parent DB, lockVersion interface{}) CacheDB {
db := &CacheDB{ db := &cacheDB{
cache: make(map[string]cDBValue), cache: make(map[string]cDBValue),
parent: parent, parent: parent,
lockVersion: lockVersion, lockVersion: lockVersion,
@ -42,7 +43,7 @@ func NewCacheDB(parent DB, lockVersion interface{}) *CacheDB {
return db return db
} }
func (db *CacheDB) Get(key []byte) []byte { func (db *cacheDB) Get(key []byte) []byte {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
@ -55,54 +56,54 @@ func (db *CacheDB) Get(key []byte) []byte {
return dbValue.value return dbValue.value
} }
func (db *CacheDB) Set(key []byte, value []byte) { func (db *cacheDB) Set(key []byte, value []byte) {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
db.SetNoLock(key, value) db.SetNoLock(key, value)
} }
func (db *CacheDB) SetSync(key []byte, value []byte) { func (db *cacheDB) SetSync(key []byte, value []byte) {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
db.SetNoLock(key, value) db.SetNoLock(key, value)
} }
func (db *CacheDB) SetNoLock(key []byte, value []byte) { func (db *cacheDB) SetNoLock(key []byte, value []byte) {
db.cache[string(key)] = cDBValue{value: value, deleted: false, dirty: true} db.cache[string(key)] = cDBValue{value: value, deleted: false, dirty: true}
} }
func (db *CacheDB) Delete(key []byte) { func (db *cacheDB) Delete(key []byte) {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
db.DeleteNoLock(key) db.DeleteNoLock(key)
} }
func (db *CacheDB) DeleteSync(key []byte) { func (db *cacheDB) DeleteSync(key []byte) {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
db.DeleteNoLock(key) db.DeleteNoLock(key)
} }
func (db *CacheDB) DeleteNoLock(key []byte) { func (db *cacheDB) DeleteNoLock(key []byte) {
db.cache[string(key)] = cDBValue{value: nil, deleted: true, dirty: true} db.cache[string(key)] = cDBValue{value: nil, deleted: true, dirty: true}
} }
func (db *CacheDB) Close() { func (db *cacheDB) Close() {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
db.parent.Close() db.parent.Close()
} }
func (db *CacheDB) Print() { func (db *cacheDB) Print() {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
fmt.Println("CacheDB\ncache:") fmt.Println("cacheDB\ncache:")
for key, value := range db.cache { for key, value := range db.cache {
fmt.Printf("[%X]:\t[%v]\n", []byte(key), value) fmt.Printf("[%X]:\t[%v]\n", []byte(key), value)
} }
@ -110,7 +111,7 @@ func (db *CacheDB) Print() {
db.parent.Print() db.parent.Print()
} }
func (db *CacheDB) Stats() map[string]string { func (db *cacheDB) Stats() map[string]string {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
@ -121,30 +122,30 @@ func (db *CacheDB) Stats() map[string]string {
return stats return stats
} }
func (db *CacheDB) Iterator() Iterator { func (db *cacheDB) Iterator() Iterator {
panic("CacheDB.Iterator() not yet supported") panic("cacheDB.Iterator() not yet supported")
} }
func (db *CacheDB) NewBatch() Batch { func (db *cacheDB) NewBatch() Batch {
return &memBatch{db, nil} return &memBatch{db, nil}
} }
// Implements `atomicSetDeleter` for Batch support. // Implements `atomicSetDeleter` for Batch support.
func (db *CacheDB) Mutex() *sync.Mutex { func (db *cacheDB) Mutex() *sync.Mutex {
return &(db.mtx) return &(db.mtx)
} }
// Write writes pending updates to the parent database and clears the cache. // Write writes pending updates to the parent database and clears the cache.
func (db *CacheDB) Write() { func (db *cacheDB) Write() {
db.mtx.Lock() db.mtx.Lock()
defer db.mtx.Unlock() defer db.mtx.Unlock()
// Optional sanity check to ensure that CacheDB is valid // Optional sanity check to ensure that cacheDB is valid
if parent, ok := db.parent.(WriteLocker); ok { if parent, ok := db.parent.(WriteLocker); ok {
if parent.TryWriteLock(db.lockVersion) { if parent.TryWriteLock(db.lockVersion) {
// All good! // All good!
} else { } else {
panic("CacheDB.Write() failed. Did this CacheDB expire?") panic("cacheDB.Write() failed. Did this CacheDB expire?")
} }
} }
@ -176,14 +177,14 @@ func (db *CacheDB) Write() {
} }
//---------------------------------------- //----------------------------------------
// To CacheWrap this CacheDB further. // To cache-wrap this cacheDB further.
func (db *CacheDB) CacheWrap() interface{} { func (db *cacheDB) CacheDB() CacheDB {
return NewCacheDB(db, db.GetWriteLockVersion()) return NewCacheDB(db, db.GetWriteLockVersion())
} }
// If the parent parent DB implements this, (e.g. such as a CacheDB parent to a // If the parent parent DB implements this, (e.g. such as a cacheDB parent to a
// CacheDB child), CacheDB will call `parent.TryWriteLock()` before attempting // cacheDB child), cacheDB will call `parent.TryWriteLock()` before attempting
// to write. // to write.
type WriteLocker interface { type WriteLocker interface {
GetWriteLockVersion() (lockVersion interface{}) GetWriteLockVersion() (lockVersion interface{})

View File

@ -10,7 +10,7 @@ func bz(s string) []byte { return []byte(s) }
func TestCacheDB(t *testing.T) { func TestCacheDB(t *testing.T) {
mem := NewMemDB() mem := NewMemDB()
cdb := mem.CacheWrap().(*CacheDB) cdb := mem.CacheDB()
require.Empty(t, cdb.Get(bz("key1")), "Expected `key1` to be empty") require.Empty(t, cdb.Get(bz("key1")), "Expected `key1` to be empty")
@ -27,7 +27,7 @@ func TestCacheDB(t *testing.T) {
require.Panics(t, func() { cdb.Write() }, "Expected second cdb.Write() to fail") require.Panics(t, func() { cdb.Write() }, "Expected second cdb.Write() to fail")
cdb = mem.CacheWrap().(*CacheDB) cdb = mem.CacheDB()
cdb.Delete(bz("key1")) cdb.Delete(bz("key1"))
require.Empty(t, cdb.Get(bz("key1"))) require.Empty(t, cdb.Get(bz("key1")))
require.Equal(t, mem.Get(bz("key1")), bz("value2")) require.Equal(t, mem.Get(bz("key1")), bz("value2"))
@ -39,33 +39,33 @@ func TestCacheDB(t *testing.T) {
func TestCacheDBWriteLock(t *testing.T) { func TestCacheDBWriteLock(t *testing.T) {
mem := NewMemDB() mem := NewMemDB()
cdb := mem.CacheWrap().(*CacheDB) cdb := mem.CacheDB()
require.NotPanics(t, func() { cdb.Write() }) require.NotPanics(t, func() { cdb.Write() })
require.Panics(t, func() { cdb.Write() }) require.Panics(t, func() { cdb.Write() })
cdb = mem.CacheWrap().(*CacheDB) cdb = mem.CacheDB()
require.NotPanics(t, func() { cdb.Write() }) require.NotPanics(t, func() { cdb.Write() })
require.Panics(t, func() { cdb.Write() }) require.Panics(t, func() { cdb.Write() })
} }
func TestCacheDBWriteLockNested(t *testing.T) { func TestCacheDBWriteLockNested(t *testing.T) {
mem := NewMemDB() mem := NewMemDB()
cdb := mem.CacheWrap().(*CacheDB) cdb := mem.CacheDB()
cdb2 := cdb.CacheWrap().(*CacheDB) cdb2 := cdb.CacheDB()
require.NotPanics(t, func() { cdb2.Write() }) require.NotPanics(t, func() { cdb2.Write() })
require.Panics(t, func() { cdb2.Write() }) require.Panics(t, func() { cdb2.Write() })
cdb2 = cdb.CacheWrap().(*CacheDB) cdb2 = cdb.CacheDB()
require.NotPanics(t, func() { cdb2.Write() }) require.NotPanics(t, func() { cdb2.Write() })
require.Panics(t, func() { cdb2.Write() }) require.Panics(t, func() { cdb2.Write() })
} }
func TestCacheDBNested(t *testing.T) { func TestCacheDBNested(t *testing.T) {
mem := NewMemDB() mem := NewMemDB()
cdb := mem.CacheWrap().(*CacheDB) cdb := mem.CacheDB()
cdb.Set(bz("key1"), bz("value1")) cdb.Set(bz("key1"), bz("value1"))
require.Empty(t, mem.Get(bz("key1"))) require.Empty(t, mem.Get(bz("key1")))
require.Equal(t, bz("value1"), cdb.Get(bz("key1"))) require.Equal(t, bz("value1"), cdb.Get(bz("key1")))
cdb2 := cdb.CacheWrap().(*CacheDB) cdb2 := cdb.CacheDB()
require.Equal(t, bz("value1"), cdb2.Get(bz("key1"))) require.Equal(t, bz("value1"), cdb2.Get(bz("key1")))
cdb2.Set(bz("key1"), bz("VALUE2")) cdb2.Set(bz("key1"), bz("VALUE2"))

View File

@ -18,8 +18,13 @@ type DB interface {
// Stats returns a map of property values for all keys and the size of the cache. // Stats returns a map of property values for all keys and the size of the cache.
Stats() map[string]string Stats() map[string]string
// CacheWrap wraps the DB w/ a CacheDB. // CacheDB wraps the DB w/ a cache.
CacheWrap() interface{} CacheDB() CacheDB
}
type CacheDB interface {
DB
Write() // Write to the underlying DB
} }
type Batch interface { type Batch interface {

View File

@ -140,7 +140,7 @@ func (db *FSDB) Mutex() *sync.Mutex {
return &(db.mtx) return &(db.mtx)
} }
func (db *FSDB) CacheWrap() interface{} { func (db *FSDB) CacheDB() CacheDB {
return NewCacheDB(db, db.GetWriteLockVersion()) return NewCacheDB(db, db.GetWriteLockVersion())
} }

View File

@ -121,7 +121,7 @@ func (db *GoLevelDB) Stats() map[string]string {
return stats return stats
} }
func (db *GoLevelDB) CacheWrap() interface{} { func (db *GoLevelDB) CacheDB() CacheDB {
return NewCacheDB(db, db.GetWriteLockVersion()) return NewCacheDB(db, db.GetWriteLockVersion())
} }

View File

@ -114,7 +114,7 @@ func (db *MemDB) Mutex() *sync.Mutex {
return &(db.mtx) return &(db.mtx)
} }
func (db *MemDB) CacheWrap() interface{} { func (db *MemDB) CacheDB() CacheDB {
return NewCacheDB(db, db.GetWriteLockVersion()) return NewCacheDB(db, db.GetWriteLockVersion())
} }