|
@@ -38,27 +38,27 @@ import (
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
const (
|
|
|
- // leveldbDegradationWarnInterval specifies how often warning should be printed
|
|
|
|
|
- // if the leveldb database cannot keep up with requested writes.
|
|
|
|
|
- leveldbDegradationWarnInterval = time.Minute
|
|
|
|
|
|
|
+ // degradationWarnInterval specifies how often warning should be printed if the
|
|
|
|
|
+ // leveldb database cannot keep up with requested writes.
|
|
|
|
|
+ degradationWarnInterval = time.Minute
|
|
|
|
|
|
|
|
- // leveldbMinCache is the minimum amount of memory in megabytes to allocate to
|
|
|
|
|
- // leveldb read and write caching, split half and half.
|
|
|
|
|
- leveldbMinCache = 16
|
|
|
|
|
|
|
+ // minCache is the minimum amount of memory in megabytes to allocate to leveldb
|
|
|
|
|
+ // read and write caching, split half and half.
|
|
|
|
|
+ minCache = 16
|
|
|
|
|
|
|
|
- // leveldbMinHandles is the minimum number of files handles to allocate to the
|
|
|
|
|
- // open database files.
|
|
|
|
|
- leveldbMinHandles = 16
|
|
|
|
|
|
|
+ // minHandles is the minimum number of files handles to allocate to the open
|
|
|
|
|
+ // database files.
|
|
|
|
|
+ minHandles = 16
|
|
|
|
|
|
|
|
// metricsGatheringInterval specifies the interval to retrieve leveldb database
|
|
// metricsGatheringInterval specifies the interval to retrieve leveldb database
|
|
|
// compaction, io and pause stats to report to the user.
|
|
// compaction, io and pause stats to report to the user.
|
|
|
metricsGatheringInterval = 3 * time.Second
|
|
metricsGatheringInterval = 3 * time.Second
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// LevelDBDatabase is a persistent key-value store. Apart from basic data storage
|
|
|
|
|
|
|
+// Database is a persistent key-value store. Apart from basic data storage
|
|
|
// functionality it also supports batch writes and iterating over the keyspace in
|
|
// functionality it also supports batch writes and iterating over the keyspace in
|
|
|
// binary-alphabetical order.
|
|
// binary-alphabetical order.
|
|
|
-type LevelDBDatabase struct {
|
|
|
|
|
|
|
+type Database struct {
|
|
|
fn string // filename for reporting
|
|
fn string // filename for reporting
|
|
|
db *leveldb.DB // LevelDB instance
|
|
db *leveldb.DB // LevelDB instance
|
|
|
|
|
|
|
@@ -78,13 +78,13 @@ type LevelDBDatabase struct {
|
|
|
|
|
|
|
|
// New returns a wrapped LevelDB object. The namespace is the prefix that the
|
|
// New returns a wrapped LevelDB object. The namespace is the prefix that the
|
|
|
// metrics reporting should use for surfacing internal stats.
|
|
// metrics reporting should use for surfacing internal stats.
|
|
|
-func New(file string, cache int, handles int, namespace string) (*LevelDBDatabase, error) {
|
|
|
|
|
|
|
+func New(file string, cache int, handles int, namespace string) (*Database, error) {
|
|
|
// Ensure we have some minimal caching and file guarantees
|
|
// Ensure we have some minimal caching and file guarantees
|
|
|
- if cache < leveldbMinCache {
|
|
|
|
|
- cache = leveldbMinCache
|
|
|
|
|
|
|
+ if cache < minCache {
|
|
|
|
|
+ cache = minCache
|
|
|
}
|
|
}
|
|
|
- if handles < leveldbMinHandles {
|
|
|
|
|
- handles = leveldbMinHandles
|
|
|
|
|
|
|
+ if handles < minHandles {
|
|
|
|
|
+ handles = minHandles
|
|
|
}
|
|
}
|
|
|
logger := log.New("database", file)
|
|
logger := log.New("database", file)
|
|
|
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
|
|
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
|
|
@@ -103,7 +103,7 @@ func New(file string, cache int, handles int, namespace string) (*LevelDBDatabas
|
|
|
return nil, err
|
|
return nil, err
|
|
|
}
|
|
}
|
|
|
// Assemble the wrapper with all the registered metrics
|
|
// Assemble the wrapper with all the registered metrics
|
|
|
- ldb := &LevelDBDatabase{
|
|
|
|
|
|
|
+ ldb := &Database{
|
|
|
fn: file,
|
|
fn: file,
|
|
|
db: db,
|
|
db: db,
|
|
|
log: logger,
|
|
log: logger,
|
|
@@ -124,7 +124,7 @@ func New(file string, cache int, handles int, namespace string) (*LevelDBDatabas
|
|
|
|
|
|
|
|
// Close stops the metrics collection, flushes any pending data to disk and closes
|
|
// Close stops the metrics collection, flushes any pending data to disk and closes
|
|
|
// all io accesses to the underlying key-value store.
|
|
// all io accesses to the underlying key-value store.
|
|
|
-func (db *LevelDBDatabase) Close() error {
|
|
|
|
|
|
|
+func (db *Database) Close() error {
|
|
|
db.quitLock.Lock()
|
|
db.quitLock.Lock()
|
|
|
defer db.quitLock.Unlock()
|
|
defer db.quitLock.Unlock()
|
|
|
|
|
|
|
@@ -140,12 +140,12 @@ func (db *LevelDBDatabase) Close() error {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Has retrieves if a key is present in the key-value store.
|
|
// Has retrieves if a key is present in the key-value store.
|
|
|
-func (db *LevelDBDatabase) Has(key []byte) (bool, error) {
|
|
|
|
|
|
|
+func (db *Database) Has(key []byte) (bool, error) {
|
|
|
return db.db.Has(key, nil)
|
|
return db.db.Has(key, nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Get retrieves the given key if it's present in the key-value store.
|
|
// Get retrieves the given key if it's present in the key-value store.
|
|
|
-func (db *LevelDBDatabase) Get(key []byte) ([]byte, error) {
|
|
|
|
|
|
|
+func (db *Database) Get(key []byte) ([]byte, error) {
|
|
|
dat, err := db.db.Get(key, nil)
|
|
dat, err := db.db.Get(key, nil)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, err
|
|
return nil, err
|
|
@@ -154,19 +154,19 @@ func (db *LevelDBDatabase) Get(key []byte) ([]byte, error) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Put inserts the given value into the key-value store.
|
|
// Put inserts the given value into the key-value store.
|
|
|
-func (db *LevelDBDatabase) Put(key []byte, value []byte) error {
|
|
|
|
|
|
|
+func (db *Database) Put(key []byte, value []byte) error {
|
|
|
return db.db.Put(key, value, nil)
|
|
return db.db.Put(key, value, nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Delete removes the key from the key-value store.
|
|
// Delete removes the key from the key-value store.
|
|
|
-func (db *LevelDBDatabase) Delete(key []byte) error {
|
|
|
|
|
|
|
+func (db *Database) Delete(key []byte) error {
|
|
|
return db.db.Delete(key, nil)
|
|
return db.db.Delete(key, nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NewBatch creates a write-only key-value store that buffers changes to its host
|
|
// NewBatch creates a write-only key-value store that buffers changes to its host
|
|
|
// database until a final write is called.
|
|
// database until a final write is called.
|
|
|
-func (db *LevelDBDatabase) NewBatch() ethdb.Batch {
|
|
|
|
|
- return &levelDBBatch{
|
|
|
|
|
|
|
+func (db *Database) NewBatch() ethdb.Batch {
|
|
|
|
|
+ return &batch{
|
|
|
db: db.db,
|
|
db: db.db,
|
|
|
b: new(leveldb.Batch),
|
|
b: new(leveldb.Batch),
|
|
|
}
|
|
}
|
|
@@ -174,18 +174,18 @@ func (db *LevelDBDatabase) NewBatch() ethdb.Batch {
|
|
|
|
|
|
|
|
// NewIterator creates a binary-alphabetical iterator over the entire keyspace
|
|
// NewIterator creates a binary-alphabetical iterator over the entire keyspace
|
|
|
// contained within the leveldb database.
|
|
// contained within the leveldb database.
|
|
|
-func (db *LevelDBDatabase) NewIterator() ethdb.Iterator {
|
|
|
|
|
|
|
+func (db *Database) NewIterator() ethdb.Iterator {
|
|
|
return db.NewIteratorWithPrefix(nil)
|
|
return db.NewIteratorWithPrefix(nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
|
|
// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
|
|
|
// of database content with a particular key prefix.
|
|
// of database content with a particular key prefix.
|
|
|
-func (db *LevelDBDatabase) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator {
|
|
|
|
|
|
|
+func (db *Database) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator {
|
|
|
return db.db.NewIterator(util.BytesPrefix(prefix), nil)
|
|
return db.db.NewIterator(util.BytesPrefix(prefix), nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Stat returns a particular internal stat of the database.
|
|
// Stat returns a particular internal stat of the database.
|
|
|
-func (db *LevelDBDatabase) Stat(property string) (string, error) {
|
|
|
|
|
|
|
+func (db *Database) Stat(property string) (string, error) {
|
|
|
return db.db.GetProperty(property)
|
|
return db.db.GetProperty(property)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -196,12 +196,12 @@ func (db *LevelDBDatabase) Stat(property string) (string, error) {
|
|
|
// A nil start is treated as a key before all keys in the data store; a nil limit
|
|
// A nil start is treated as a key before all keys in the data store; a nil limit
|
|
|
// is treated as a key after all keys in the data store. If both is nil then it
|
|
// is treated as a key after all keys in the data store. If both is nil then it
|
|
|
// will compact entire data store.
|
|
// will compact entire data store.
|
|
|
-func (db *LevelDBDatabase) Compact(start []byte, limit []byte) error {
|
|
|
|
|
|
|
+func (db *Database) Compact(start []byte, limit []byte) error {
|
|
|
return db.db.CompactRange(util.Range{Start: start, Limit: limit})
|
|
return db.db.CompactRange(util.Range{Start: start, Limit: limit})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Path returns the path to the database directory.
|
|
// Path returns the path to the database directory.
|
|
|
-func (db *LevelDBDatabase) Path() string {
|
|
|
|
|
|
|
+func (db *Database) Path() string {
|
|
|
return db.fn
|
|
return db.fn
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -222,7 +222,7 @@ func (db *LevelDBDatabase) Path() string {
|
|
|
//
|
|
//
|
|
|
// This is how the iostats look like (currently):
|
|
// This is how the iostats look like (currently):
|
|
|
// Read(MB):3895.04860 Write(MB):3654.64712
|
|
// Read(MB):3895.04860 Write(MB):3654.64712
|
|
|
-func (db *LevelDBDatabase) meter(refresh time.Duration) {
|
|
|
|
|
|
|
+func (db *Database) meter(refresh time.Duration) {
|
|
|
// Create the counters to store current and previous compaction values
|
|
// Create the counters to store current and previous compaction values
|
|
|
compactions := make([][]float64, 2)
|
|
compactions := make([][]float64, 2)
|
|
|
for i := 0; i < 2; i++ {
|
|
for i := 0; i < 2; i++ {
|
|
@@ -326,7 +326,7 @@ func (db *LevelDBDatabase) meter(refresh time.Duration) {
|
|
|
// If a warning that db is performing compaction has been displayed, any subsequent
|
|
// If a warning that db is performing compaction has been displayed, any subsequent
|
|
|
// warnings will be withheld for one minute not to overwhelm the user.
|
|
// warnings will be withheld for one minute not to overwhelm the user.
|
|
|
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
|
|
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
|
|
|
- time.Now().After(lastWritePaused.Add(leveldbDegradationWarnInterval)) {
|
|
|
|
|
|
|
+ time.Now().After(lastWritePaused.Add(degradationWarnInterval)) {
|
|
|
db.log.Warn("Database compacting, degraded performance")
|
|
db.log.Warn("Database compacting, degraded performance")
|
|
|
lastWritePaused = time.Now()
|
|
lastWritePaused = time.Now()
|
|
|
}
|
|
}
|
|
@@ -379,40 +379,40 @@ func (db *LevelDBDatabase) meter(refresh time.Duration) {
|
|
|
errc <- merr
|
|
errc <- merr
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// levelDBBatch is a write-only leveldb batch that commits changes to its host
|
|
|
|
|
-// database when Write is called. A batch cannot be used concurrently.
|
|
|
|
|
-type levelDBBatch struct {
|
|
|
|
|
|
|
+// batch is a write-only leveldb batch that commits changes to its host database
|
|
|
|
|
+// when Write is called. A batch cannot be used concurrently.
|
|
|
|
|
+type batch struct {
|
|
|
db *leveldb.DB
|
|
db *leveldb.DB
|
|
|
b *leveldb.Batch
|
|
b *leveldb.Batch
|
|
|
size int
|
|
size int
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Put inserts the given value into the batch for later committing.
|
|
// Put inserts the given value into the batch for later committing.
|
|
|
-func (b *levelDBBatch) Put(key, value []byte) error {
|
|
|
|
|
|
|
+func (b *batch) Put(key, value []byte) error {
|
|
|
b.b.Put(key, value)
|
|
b.b.Put(key, value)
|
|
|
b.size += len(value)
|
|
b.size += len(value)
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Delete inserts the a key removal into the batch for later committing.
|
|
// Delete inserts the a key removal into the batch for later committing.
|
|
|
-func (b *levelDBBatch) Delete(key []byte) error {
|
|
|
|
|
|
|
+func (b *batch) Delete(key []byte) error {
|
|
|
b.b.Delete(key)
|
|
b.b.Delete(key)
|
|
|
- b.size += 1
|
|
|
|
|
|
|
+ b.size++
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ValueSize retrieves the amount of data queued up for writing.
|
|
// ValueSize retrieves the amount of data queued up for writing.
|
|
|
-func (b *levelDBBatch) ValueSize() int {
|
|
|
|
|
|
|
+func (b *batch) ValueSize() int {
|
|
|
return b.size
|
|
return b.size
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Write flushes any accumulated data to disk.
|
|
// Write flushes any accumulated data to disk.
|
|
|
-func (b *levelDBBatch) Write() error {
|
|
|
|
|
|
|
+func (b *batch) Write() error {
|
|
|
return b.db.Write(b.b, nil)
|
|
return b.db.Write(b.b, nil)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Reset resets the batch for reuse.
|
|
// Reset resets the batch for reuse.
|
|
|
-func (b *levelDBBatch) Reset() {
|
|
|
|
|
|
|
+func (b *batch) Reset() {
|
|
|
b.b.Reset()
|
|
b.b.Reset()
|
|
|
b.size = 0
|
|
b.size = 0
|
|
|
}
|
|
}
|