// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package rawdb import ( "fmt" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/ethdb/memorydb" ) // freezerdb is a database wrapper that enabled freezer data retrievals. type freezerdb struct { ethdb.KeyValueStore 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. type nofreezedb struct { ethdb.KeyValueStore } // HasAncient returns an error as we don't have a backing chain freezer. func (db *nofreezedb) HasAncient(kind string, number uint64) (bool, error) { return false, errNotSupported } // Ancient returns an error as we don't have a backing chain freezer. func (db *nofreezedb) Ancient(kind string, number uint64) ([]byte, error) { return nil, errNotSupported } // Ancients returns an error as we don't have a backing chain freezer. func (db *nofreezedb) Ancients() (uint64, error) { return 0, errNotSupported } // AppendAncient returns an error as we don't have a backing chain freezer. func (db *nofreezedb) AppendAncient(number uint64, hash, header, body, receipts, td []byte) error { return errNotSupported } // TruncateAncients returns an error as we don't have a backing chain freezer. func (db *nofreezedb) TruncateAncients(items uint64) error { return errNotSupported } // Sync returns an error as we don't have a backing chain freezer. func (db *nofreezedb) Sync() error { return errNotSupported } // NewDatabase creates a high level database on top of a given key-value data // store without a freezer moving immutable chain segments into cold storage. func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { return &nofreezedb{ KeyValueStore: db, } } // NewDatabaseWithFreezer creates a high level database on top of a given key- // value data store with a freezer moving immutable chain segments into cold // storage. func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string) (ethdb.Database, error) { frdb, err := newFreezer(freezer, namespace) if err != nil { return nil, err } go frdb.freeze(db) return &freezerdb{ KeyValueStore: db, AncientStore: frdb, }, nil } // NewMemoryDatabase creates an ephemeral in-memory key-value database without a // freezer moving immutable chain segments into cold storage. func NewMemoryDatabase() ethdb.Database { return NewDatabase(memorydb.New()) } // NewMemoryDatabaseWithCap creates an ephemeral in-memory key-value database // with an initial starting capacity, but without a freezer moving immutable // chain segments into cold storage. func NewMemoryDatabaseWithCap(size int) ethdb.Database { return NewDatabase(memorydb.NewWithCap(size)) } // NewLevelDBDatabase creates a persistent key-value database without a freezer // moving immutable chain segments into cold storage. func NewLevelDBDatabase(file string, cache int, handles int, namespace string) (ethdb.Database, error) { db, err := leveldb.New(file, cache, handles, namespace) if err != nil { return nil, err } return NewDatabase(db), nil } // NewLevelDBDatabaseWithFreezer creates a persistent key-value database with a // freezer moving immutable chain segments into cold storage. func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) { kvdb, err := leveldb.New(file, cache, handles, namespace) if err != nil { return nil, err } frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace) if err != nil { kvdb.Close() return nil, err } return frdb, nil }