@ -18,6 +18,7 @@ package rawdb
import (
"encoding/json"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
@ -30,7 +31,7 @@ import (
func ReadDatabaseVersion ( db ethdb . KeyValueReader ) * uint64 {
var version uint64
enc , _ := db . Get ( databaseVeri sionKey )
enc , _ := db . Get ( databaseVersionKey )
if len ( enc ) == 0 {
return nil
}
@ -47,7 +48,7 @@ func WriteDatabaseVersion(db ethdb.KeyValueWriter, version uint64) {
if err != nil {
log . Crit ( "Failed to encode database version" , "err" , err )
}
if err = db . Put ( databaseVeri sionKey , enc ) ; err != nil {
if err = db . Put ( databaseVersionKey , enc ) ; err != nil {
log . Crit ( "Failed to store the database version" , "err" , err )
}
}
@ -79,3 +80,61 @@ func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.Cha
log . Crit ( "Failed to store chain config" , "err" , err )
}
}
// crashList is a list of unclean-shutdown-markers, for rlp-encoding to the
// database
type crashList struct {
Discarded uint64 // how many ucs have we deleted
Recent [ ] uint64 // unix timestamps of 10 latest unclean shutdowns
}
const crashesToKeep = 10
// PushUncleanShutdownMarker appends a new unclean shutdown marker and returns
// the previous data
// - a list of timestamps
// - a count of how many old unclean-shutdowns have been discarded
func PushUncleanShutdownMarker ( db ethdb . KeyValueStore ) ( [ ] uint64 , uint64 , error ) {
var uncleanShutdowns crashList
// Read old data
if data , err := db . Get ( uncleanShutdownKey ) ; err != nil {
log . Warn ( "Error reading unclean shutdown markers" , "error" , err )
} else if err := rlp . DecodeBytes ( data , & uncleanShutdowns ) ; err != nil {
return nil , 0 , err
}
var discarded = uncleanShutdowns . Discarded
var previous = make ( [ ] uint64 , len ( uncleanShutdowns . Recent ) )
copy ( previous , uncleanShutdowns . Recent )
// Add a new (but cap it)
uncleanShutdowns . Recent = append ( uncleanShutdowns . Recent , uint64 ( time . Now ( ) . Unix ( ) ) )
if count := len ( uncleanShutdowns . Recent ) ; count > crashesToKeep + 1 {
numDel := count - ( crashesToKeep + 1 )
uncleanShutdowns . Recent = uncleanShutdowns . Recent [ numDel : ]
uncleanShutdowns . Discarded += uint64 ( numDel )
}
// And save it again
data , _ := rlp . EncodeToBytes ( uncleanShutdowns )
if err := db . Put ( uncleanShutdownKey , data ) ; err != nil {
log . Warn ( "Failed to write unclean-shutdown marker" , "err" , err )
return nil , 0 , err
}
return previous , discarded , nil
}
// PopUncleanShutdownMarker removes the last unclean shutdown marker
func PopUncleanShutdownMarker ( db ethdb . KeyValueStore ) {
var uncleanShutdowns crashList
// Read old data
if data , err := db . Get ( uncleanShutdownKey ) ; err != nil {
log . Warn ( "Error reading unclean shutdown markers" , "error" , err )
} else if err := rlp . DecodeBytes ( data , & uncleanShutdowns ) ; err != nil {
log . Error ( "Error decoding unclean shutdown markers" , "error" , err ) // Should mos def _not_ happen
}
if l := len ( uncleanShutdowns . Recent ) ; l > 0 {
uncleanShutdowns . Recent = uncleanShutdowns . Recent [ : l - 1 ]
}
data , _ := rlp . EncodeToBytes ( uncleanShutdowns )
if err := db . Put ( uncleanShutdownKey , data ) ; err != nil {
log . Warn ( "Failed to clear unclean-shutdown marker" , "err" , err )
}
}