Version the leveldb (and keep compatibility with pre-versioned uncompressed databases.

This commit is contained in:
Dale Rahn 2013-09-25 16:18:35 -04:00
parent 0e98349c98
commit 3640f6d37c
5 changed files with 72 additions and 2 deletions

View file

@ -16,13 +16,16 @@ import (
func TestEmptyDB(t *testing.T) { func TestEmptyDB(t *testing.T) {
dbname := "tstdbempty" dbname := "tstdbempty"
dbnamever := dbname + ".ver"
_ = os.RemoveAll(dbname) _ = os.RemoveAll(dbname)
_ = os.RemoveAll(dbnamever)
db, err := btcdb.CreateDB("leveldb", dbname) db, err := btcdb.CreateDB("leveldb", dbname)
if err != nil { if err != nil {
t.Errorf("Failed to open test database %v", err) t.Errorf("Failed to open test database %v", err)
return return
} }
defer os.RemoveAll(dbname) defer os.RemoveAll(dbname)
defer os.RemoveAll(dbnamever)
sha, height, err := db.NewestSha() sha, height, err := db.NewestSha()
if !sha.IsEqual(&btcwire.ShaHash{}) { if !sha.IsEqual(&btcwire.ShaHash{}) {

View file

@ -11,5 +11,12 @@ The performance is generally high although it goes down with database
size. size.
Many of the block or tx specific functions for btcdb are in this subpackage. Many of the block or tx specific functions for btcdb are in this subpackage.
Database version number is stored in a flat file <dbname>.ver
Currently a single (littlendian) integer in the file. If there is
additional data to save in the future, the presense of additional
data can be indicated by changing the version number, then parsing the
file differently.
*/ */
package ldb package ldb

View file

@ -46,13 +46,16 @@ func TestUnspentInsert(t *testing.T) {
func testUnspentInsert(t *testing.T, mode int) { func testUnspentInsert(t *testing.T, mode int) {
// Ignore db remove errors since it means we didn't have an old one. // Ignore db remove errors since it means we didn't have an old one.
dbname := fmt.Sprintf("tstdbuspnt1.%d", mode) dbname := fmt.Sprintf("tstdbuspnt1.%d", mode)
dbnamever := dbname + ".ver"
_ = os.RemoveAll(dbname) _ = os.RemoveAll(dbname)
_ = os.RemoveAll(dbnamever)
db, err := btcdb.CreateDB("leveldb", dbname) db, err := btcdb.CreateDB("leveldb", dbname)
if err != nil { if err != nil {
t.Errorf("Failed to open test database %v", err) t.Errorf("Failed to open test database %v", err)
return return
} }
defer os.RemoveAll(dbname) defer os.RemoveAll(dbname)
defer os.RemoveAll(dbnamever)
defer db.Close() defer db.Close()
switch mode { switch mode {

View file

@ -5,6 +5,7 @@
package ldb package ldb
import ( import (
"encoding/binary"
"fmt" "fmt"
"github.com/conformal/btcdb" "github.com/conformal/btcdb"
"github.com/conformal/btcutil" "github.com/conformal/btcutil"
@ -129,9 +130,13 @@ blocknarrow:
return db, nil return db, nil
} }
var CurrentDBVersion int32 = 1
func openDB(dbpath string, flag opt.OptionsFlag) (pbdb btcdb.Db, err error) { func openDB(dbpath string, flag opt.OptionsFlag) (pbdb btcdb.Db, err error) {
var db LevelDb var db LevelDb
var tlDb *leveldb.DB var tlDb *leveldb.DB
var dbversion int32
defer func() { defer func() {
if err == nil { if err == nil {
db.lDb = tlDb db.lDb = tlDb
@ -156,14 +161,60 @@ func openDB(dbpath string, flag opt.OptionsFlag) (pbdb btcdb.Db, err error) {
} }
} }
tlDb, err = leveldb.OpenFile(dbpath, &opt.Options{Flag: flag, needVersionFile := false
verfile := dbpath + ".ver"
fi, ferr := os.Open(verfile)
if ferr == nil {
defer fi.Close()
ferr = binary.Read(fi, binary.LittleEndian, &dbversion)
if ferr != nil {
dbversion = ^0
}
} else {
if flag&opt.OFCreateIfMissing != 0 {
needVersionFile = true
}
}
opts := &opt.Options{Flag: flag,
BlockCache: cache.EmptyCache{}, BlockCache: cache.EmptyCache{},
MaxOpenFiles: 256, MaxOpenFiles: 256,
CompressionType: opt.NoCompression}) CompressionType: opt.NoCompression,
}
switch dbversion {
case 0:
opts = &opt.Options{Flag: flag}
case 1:
// uses defaults from above
default:
err = fmt.Errorf("unsupported db version %v", dbversion)
return
}
tlDb, err = leveldb.OpenFile(dbpath, opts)
if err != nil { if err != nil {
return return
} }
// If we opened the database successfully on 'create'
// update the
if needVersionFile {
fo, ferr := os.Create(verfile)
if ferr != nil {
// TODO(design) close and delete database?
err = ferr
return
}
defer fo.Close()
dbversion = CurrentDBVersion
err = binary.Write(fo, binary.LittleEndian, dbversion)
if err != nil {
return
}
}
return return
} }

View file

@ -42,13 +42,16 @@ func testOperationalMode(t *testing.T, mode int) {
// Ignore db remove errors since it means we didn't have an old one. // Ignore db remove errors since it means we didn't have an old one.
dbname := fmt.Sprintf("tstdbop1.%d", mode) dbname := fmt.Sprintf("tstdbop1.%d", mode)
dbnamever := dbname + ".ver"
_ = os.RemoveAll(dbname) _ = os.RemoveAll(dbname)
_ = os.RemoveAll(dbnamever)
db, err := btcdb.CreateDB("leveldb", dbname) db, err := btcdb.CreateDB("leveldb", dbname)
if err != nil { if err != nil {
t.Errorf("Failed to open test database %v", err) t.Errorf("Failed to open test database %v", err)
return return
} }
defer os.RemoveAll(dbname) defer os.RemoveAll(dbname)
defer os.RemoveAll(dbnamever)
defer db.Close() defer db.Close()
switch mode { switch mode {
@ -177,13 +180,16 @@ func testBackout(t *testing.T, mode int) {
t.Logf("mode %v", mode) t.Logf("mode %v", mode)
// Ignore db remove errors since it means we didn't have an old one. // Ignore db remove errors since it means we didn't have an old one.
dbname := fmt.Sprintf("tstdbop2.%d", mode) dbname := fmt.Sprintf("tstdbop2.%d", mode)
dbnamever := dbname + ".ver"
_ = os.RemoveAll(dbname) _ = os.RemoveAll(dbname)
_ = os.RemoveAll(dbnamever)
db, err := btcdb.CreateDB("leveldb", dbname) db, err := btcdb.CreateDB("leveldb", dbname)
if err != nil { if err != nil {
t.Errorf("Failed to open test database %v", err) t.Errorf("Failed to open test database %v", err)
return return
} }
defer os.RemoveAll(dbname) defer os.RemoveAll(dbname)
defer os.RemoveAll(dbnamever)
defer db.Close() defer db.Close()
switch mode { switch mode {