package db import ( "bytes" "fmt" "sync" ) // IteratePrefix is a convenience function for iterating over a key domain // restricted by prefix. func IteratePrefix(db DB, prefix []byte) Iterator { var start, end []byte if len(prefix) == 0 { start = nil end = nil } else { start = cp(prefix) end = cpIncr(prefix) } return db.Iterator(start, end) } /* TODO: Make test, maybe rename. // Like IteratePrefix but the iterator strips the prefix from the keys. func IteratePrefixStripped(db DB, prefix []byte) Iterator { return newUnprefixIterator(prefix, IteratePrefix(db, prefix)) } */ //---------------------------------------- // prefixDB type prefixDB struct { mtx sync.Mutex prefix []byte db DB } // NewPrefixDB lets you namespace multiple DBs within a single DB. func NewPrefixDB(db DB, prefix []byte) *prefixDB { return &prefixDB{ prefix: prefix, db: db, } } // Implements atomicSetDeleter. func (pdb *prefixDB) Mutex() *sync.Mutex { return &(pdb.mtx) } // Implements DB. func (pdb *prefixDB) Get(key []byte) []byte { pdb.mtx.Lock() defer pdb.mtx.Unlock() return pdb.db.Get(pdb.prefixed(key)) } // Implements DB. func (pdb *prefixDB) Has(key []byte) bool { pdb.mtx.Lock() defer pdb.mtx.Unlock() return pdb.db.Has(pdb.prefixed(key)) } // Implements DB. func (pdb *prefixDB) Set(key []byte, value []byte) { pdb.mtx.Lock() defer pdb.mtx.Unlock() pdb.db.Set(pdb.prefixed(key), value) } // Implements DB. func (pdb *prefixDB) SetSync(key []byte, value []byte) { pdb.mtx.Lock() defer pdb.mtx.Unlock() pdb.db.SetSync(pdb.prefixed(key), value) } // Implements atomicSetDeleter. func (pdb *prefixDB) SetNoLock(key []byte, value []byte) { pdb.db.Set(pdb.prefixed(key), value) } // Implements atomicSetDeleter. func (pdb *prefixDB) SetNoLockSync(key []byte, value []byte) { pdb.db.SetSync(pdb.prefixed(key), value) } // Implements DB. func (pdb *prefixDB) Delete(key []byte) { pdb.mtx.Lock() defer pdb.mtx.Unlock() pdb.db.Delete(pdb.prefixed(key)) } // Implements DB. func (pdb *prefixDB) DeleteSync(key []byte) { pdb.mtx.Lock() defer pdb.mtx.Unlock() pdb.db.DeleteSync(pdb.prefixed(key)) } // Implements atomicSetDeleter. func (pdb *prefixDB) DeleteNoLock(key []byte) { pdb.db.Delete(pdb.prefixed(key)) } // Implements atomicSetDeleter. func (pdb *prefixDB) DeleteNoLockSync(key []byte) { pdb.db.DeleteSync(pdb.prefixed(key)) } // Implements DB. func (pdb *prefixDB) Iterator(start, end []byte) Iterator { pdb.mtx.Lock() defer pdb.mtx.Unlock() pstart := append(pdb.prefix, start...) pend := []byte(nil) if end != nil { pend = append(pdb.prefix, end...) } return newUnprefixIterator( pdb.prefix, pdb.db.Iterator( pstart, pend, ), ) } // Implements DB. func (pdb *prefixDB) ReverseIterator(start, end []byte) Iterator { pdb.mtx.Lock() defer pdb.mtx.Unlock() pstart := []byte(nil) if start != nil { pstart = append(pdb.prefix, start...) } pend := []byte(nil) if end != nil { pend = append(pdb.prefix, end...) } return newUnprefixIterator( pdb.prefix, pdb.db.ReverseIterator( pstart, pend, ), ) } // Implements DB. func (pdb *prefixDB) NewBatch() Batch { pdb.mtx.Lock() defer pdb.mtx.Unlock() return &memBatch{pdb, nil} } // Implements DB. func (pdb *prefixDB) Close() { pdb.mtx.Lock() defer pdb.mtx.Unlock() pdb.db.Close() } // Implements DB. func (pdb *prefixDB) Print() { fmt.Printf("prefix: %X\n", pdb.prefix) itr := pdb.Iterator(nil, nil) defer itr.Close() for ; itr.Valid(); itr.Next() { key := itr.Key() value := itr.Value() fmt.Printf("[%X]:\t[%X]\n", key, value) } } // Implements DB. func (pdb *prefixDB) Stats() map[string]string { stats := make(map[string]string) stats["prefixdb.prefix.string"] = string(pdb.prefix) stats["prefixdb.prefix.hex"] = fmt.Sprintf("%X", pdb.prefix) source := pdb.db.Stats() for key, value := range source { stats["prefixdb.source."+key] = value } return stats } func (pdb *prefixDB) prefixed(key []byte) []byte { return append(pdb.prefix, key...) } //---------------------------------------- // Strips prefix while iterating from Iterator. type unprefixIterator struct { prefix []byte source Iterator } func newUnprefixIterator(prefix []byte, source Iterator) unprefixIterator { return unprefixIterator{ prefix: prefix, source: source, } } func (itr unprefixIterator) Domain() (start []byte, end []byte) { start, end = itr.source.Domain() if len(start) > 0 { start = stripPrefix(start, itr.prefix) } if len(end) > 0 { end = stripPrefix(end, itr.prefix) } return } func (itr unprefixIterator) Valid() bool { return itr.source.Valid() } func (itr unprefixIterator) Next() { itr.source.Next() } func (itr unprefixIterator) Key() (key []byte) { return stripPrefix(itr.source.Key(), itr.prefix) } func (itr unprefixIterator) Value() (value []byte) { return itr.source.Value() } func (itr unprefixIterator) Close() { itr.source.Close() } //---------------------------------------- func stripPrefix(key []byte, prefix []byte) (stripped []byte) { if len(key) < len(prefix) { panic("should not happen") } if !bytes.Equal(key[:len(prefix)], prefix) { panic("should not happne") } return key[len(prefix):] }