core/rawdb: add file lock for freezer

This commit is contained in:
rjl493456442 2019-03-14 14:59:47 +08:00 committed by Péter Szilágyi
parent b69bdc2a4f
commit b6cac42e9f
No known key found for this signature in database
GPG Key ID: E9AE538CEDF8293D
3 changed files with 43 additions and 5 deletions

View File

@ -17,6 +17,8 @@
package rawdb package rawdb
import ( import (
"fmt"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/ethdb/leveldb"
"github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/ethdb/memorydb"
@ -25,7 +27,23 @@ import (
// freezerdb is a databse wrapper that enabled freezer data retrievals. // freezerdb is a databse wrapper that enabled freezer data retrievals.
type freezerdb struct { type freezerdb struct {
ethdb.KeyValueStore ethdb.KeyValueStore
ethdb.Ancienter ethdb.AncientStore
}
// Close implements io.Closer, closing both the fast key-value store as well as
// the slow ancient tables.
func (frdb *freezerdb) Close() error {
var errs []error
if err := frdb.KeyValueStore.Close(); err != nil {
errs = append(errs, err)
}
if err := frdb.AncientStore.Close(); err != nil {
errs = append(errs, err)
}
if len(errs) != 0 {
return fmt.Errorf("%v", errs)
}
return nil
} }
// nofreezedb is a database wrapper that disables freezer data retrievals. // nofreezedb is a database wrapper that disables freezer data retrievals.
@ -58,7 +76,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st
return &freezerdb{ return &freezerdb{
KeyValueStore: db, KeyValueStore: db,
Ancienter: frdb, AncientStore: frdb,
}, nil }, nil
} }

View File

@ -20,6 +20,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"path/filepath"
"sync/atomic" "sync/atomic"
"time" "time"
@ -27,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/prometheus/tsdb/fileutil"
) )
// errUnknownTable is returned if the user attempts to read from a table that is // errUnknownTable is returned if the user attempts to read from a table that is
@ -57,8 +59,9 @@ const (
// reserving it for go-ethereum. This would also reduce the memory requirements // reserving it for go-ethereum. This would also reduce the memory requirements
// of Geth, and thus also GC overhead. // of Geth, and thus also GC overhead.
type freezer struct { type freezer struct {
tables map[string]*freezerTable // Data tables for storing everything tables map[string]*freezerTable // Data tables for storing everything
frozen uint64 // Number of blocks already frozen frozen uint64 // Number of blocks already frozen
instanceLock fileutil.Releaser // File-system lock to prevent double opens
} }
// newFreezer creates a chain freezer that moves ancient chain data into // newFreezer creates a chain freezer that moves ancient chain data into
@ -69,9 +72,14 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil) readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
writeMeter = metrics.NewRegisteredMeter(namespace+"ancient/write", nil) writeMeter = metrics.NewRegisteredMeter(namespace+"ancient/write", nil)
) )
lock, _, err := fileutil.Flock(filepath.Join(datadir, "LOCK"))
if err != nil {
return nil, err
}
// Open all the supported data tables // Open all the supported data tables
freezer := &freezer{ freezer := &freezer{
tables: make(map[string]*freezerTable), tables: make(map[string]*freezerTable),
instanceLock: lock,
} }
for _, name := range []string{"hashes", "headers", "bodies", "receipts", "diffs"} { for _, name := range []string{"hashes", "headers", "bodies", "receipts", "diffs"} {
table, err := newTable(datadir, name, readMeter, writeMeter) table, err := newTable(datadir, name, readMeter, writeMeter)
@ -79,6 +87,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
for _, table := range freezer.tables { for _, table := range freezer.tables {
table.Close() table.Close()
} }
lock.Release()
return nil, err return nil, err
} }
freezer.tables[name] = table freezer.tables[name] = table
@ -95,6 +104,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
for _, table := range freezer.tables { for _, table := range freezer.tables {
table.Close() table.Close()
} }
lock.Release()
return nil, err return nil, err
} }
} }
@ -109,6 +119,9 @@ func (f *freezer) Close() error {
errs = append(errs, err) errs = append(errs, err)
} }
} }
if err := f.instanceLock.Release(); err != nil {
errs = append(errs, err)
}
if errs != nil { if errs != nil {
return fmt.Errorf("%v", errs) return fmt.Errorf("%v", errs)
} }

View File

@ -80,6 +80,13 @@ type AncientReader interface {
Ancienter Ancienter
} }
// AncientStore contains all the methods required to allow handling different
// ancient data stores backing immutable chain data store.
type AncientStore interface {
Ancienter
io.Closer
}
// Database contains all the methods required by the high level database to not // Database contains all the methods required by the high level database to not
// only access the key-value data store but also the chain freezer. // only access the key-value data store but also the chain freezer.
type Database interface { type Database interface {