Skip to content

Commit

Permalink
cleaner and passing
Browse files Browse the repository at this point in the history
  • Loading branch information
Sarah Christoff committed Apr 21, 2021
1 parent a4afc14 commit 7935e82
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 66 deletions.
6 changes: 0 additions & 6 deletions bolt_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,3 @@ func (b *BoltStore) GetUint64(key []byte) (uint64, error) {
func (b *BoltStore) Sync() error {
return b.conn.Sync()
}

// InternalUseOnlyAccessBoltDB is used for the v2/transition function
// WARNING: THIS IS ONLY TO BE USED BY THAT FUNCTION
func (b *BoltStore) InternalUseOnlyAccessBoltDB() *bolt.DB {
return b.conn
}
80 changes: 53 additions & 27 deletions v2/bolt_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package raftboltdb

import (
"errors"
"fmt"
"os"
"time"

boltdbbolt "github.com/boltdb/bolt"
"github.com/hashicorp/raft"
v1 "github.com/hashicorp/raft-boltdb"
"go.etcd.io/bbolt"
)

Expand Down Expand Up @@ -268,43 +271,66 @@ func (b *BoltStore) Sync() error {
return b.conn.Sync()
}

// Transition takes a BoltDB and a path, and outputs a
// Bbolt and generates it at that path
func Transition(old *v1.BoltStore, path string) (*BoltStore, error) {

//Create the bbolt log store
newbolt, err := New(Options{Path: path})

//Grab connection to the old store
oldconn := old.InternalUseOnlyAccessBoltDB()
// MigratetoV2 reads in the source file path of a BoltDB file
// and outputs all the data migrated to a Bbolt destination file
func MigratetoV2(source, destination string) (*BoltStore, error) {
_, err := os.Stat(destination)
if err == nil {
return nil, fmt.Errorf("file exists in destination %v", destination)
}

//Start a connection to the old
oldtx, err := oldconn.Begin(false)
sourceDb, err := boltdbbolt.Open(source, dbFileMode, &boltdbbolt.Options{
ReadOnly: true,
Timeout: 1 * time.Minute,
})
if err != nil {
return newbolt, err
return nil, fmt.Errorf("failed opening source database: %v", err)
}

//Grab the old buckets
confBucket := oldtx.Bucket([]byte(dbConf))
logBucket := oldtx.Bucket([]byte(dbLogs))
//Start a connection to the source
sourcetx, err := sourceDb.Begin(false)
if err != nil {
return nil, fmt.Errorf("failed connecting to source database: %v", err)
}
defer sourcetx.Rollback()

//Create the destination
destDb, err := New(Options{Path: destination})
if err != nil {
return nil, fmt.Errorf("failed creating destination database: %v", err)
}
//Start a connection to the new
newtx, err := newbolt.conn.Begin(false)
desttx, err := destDb.conn.Begin(true)
if err != nil {
return newbolt, err
destDb.Close()
os.Remove(destination)
return nil, fmt.Errorf("failed connecting to destination database: %v", err)
}

defer desttx.Rollback()

//Loop over both old buckets and set them in the new
confBucket.ForEach(func(k, v []byte) error {
bucket := newtx.Bucket(dbConf)
return bucket.Put(k, v)
})
buckets := [][]byte{dbConf, dbLogs}
for _, b := range buckets {
sourceB := sourcetx.Bucket(b)
destB := desttx.Bucket(b)
err = sourceB.ForEach(func(k, v []byte) error {
return destB.Put(k, v)
})
if err != nil {
destDb.Close()
os.Remove(destination)
return nil, fmt.Errorf("failed to copy %v bucket: %v", string(b), err)
}
}

logBucket.ForEach(func(k, v []byte) error {
bucket := newtx.Bucket(dbLogs)
return bucket.Put(k, v)
})
//If the commit fails, clean up
if err := desttx.Commit(); err != nil {
destDb.Close()
os.Remove(destination)
return nil, fmt.Errorf("failed commiting data to destination: %v", err)
}

return newbolt, nil
return destDb, nil

}
60 changes: 27 additions & 33 deletions v2/bolt_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -416,65 +417,58 @@ func TestBoltStore_SetUint64_GetUint64(t *testing.T) {
}
}

func TestBoltStore_TransitionBbolt(t *testing.T) {
func TestBoltStore_MigratetoV2(t *testing.T) {

//Create BoltDB
fh, err := ioutil.TempFile("", "bolt")
dir, err := ioutil.TempDir("", t.Name())
if err != nil {
t.Fatalf("err: %s", err)
}
os.Remove(fh.Name())
defer os.Remove(fh.Name())
defer os.RemoveAll(dir)

var sourceFile, destFile string
sourceFile = filepath.Join(dir, "/sourcepath")
destFile = filepath.Join(dir, "/destpath")

// Successfully creates and returns a store
oldstore, err := v1.NewBoltStore(fh.Name())
sourceDb, err := v1.NewBoltStore(sourceFile)
if err != nil {
t.Fatalf("err: %s", err)
t.Fatalf("failed creating source database: %s", err)
}
defer sourceDb.Close()

// Set a mock raft log
log := new(raft.Log)
logs := []*raft.Log{
testRaftLog(1, "log1"),
testRaftLog(2, "log2"),
testRaftLog(3, "log3"),
}

//Store logs old
if err := oldstore.StoreLogs(logs); err != nil {
t.Fatalf("bad: %s", err)
//Store logs source
if err := sourceDb.StoreLogs(logs); err != nil {
t.Fatalf("failed storing logs in source database: %s", err)
}

// Should return the proper log
oldresult := new(raft.Log)
if err := oldstore.GetLog(2, oldresult); err != nil {
t.Fatalf("err: %s", err)
sourceResult := new(raft.Log)
if err := sourceDb.GetLog(2, sourceResult); err != nil {
t.Fatalf("failed getting log from source database: %s", err)
}

if err := oldstore.Close(); err != nil {
t.Fatalf("err: %s", err)
if err := sourceDb.Close(); err != nil {
t.Fatalf("failed closing source database: %s", err)
}

//Send to func
newstore, err := Transition(oldstore, fh.Name())
destDb, err := MigratetoV2(sourceFile, destFile)
if err != nil {
t.Fatalf("did not transition successfully, err %v", err)
}

//Store same logs in new
if err := newstore.StoreLogs(logs); err != nil {
t.Fatalf("bad: %s", err)
t.Fatalf("did not migrate successfully, err %v", err)
}
defer destDb.Close()

// Should return the proper log
newresult := new(raft.Log)
if err := newstore.GetLog(2, newresult); err != nil {
t.Fatalf("err: %s", err)
destResult := new(raft.Log)
if err := destDb.GetLog(2, destResult); err != nil {
t.Fatalf("failed getting log from destination database: %s", err)
}

//Comapre
if !reflect.DeepEqual(oldresult, newresult) {
t.Errorf("BoltDB log did not equal Bbolt log, Boltdb %v, Bbolt: %v", oldresult, newresult)
if !reflect.DeepEqual(sourceResult, destResult) {
t.Errorf("BoltDB log did not equal Bbolt log, Boltdb %v, Bbolt: %v", sourceResult, destResult)
}

}
2 changes: 2 additions & 0 deletions v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ module github.com/hashicorp/raft-boltdb/v2
go 1.12

require (
github.com/boltdb/bolt v1.3.1
github.com/hashicorp/go-msgpack v0.5.5
github.com/hashicorp/raft v1.1.0
github.com/hashicorp/raft-boltdb v0.0.0-20210409134258-03c10cc3d4ea
go.etcd.io/bbolt v1.3.5
)

0 comments on commit 7935e82

Please sign in to comment.