Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable database migration code on unsupported platforms or if the nobolt tag is present #37

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions v2/bolt_migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//go:build (386 || amd64 || arm || arm64 || ppc || ppc64 || ppc64le || s390x) && !nobolt
// +build 386 amd64 arm arm64 ppc ppc64 ppc64le s390x
// +build !nobolt

package raftboltdb

import (
"fmt"
"os"
"time"

v1 "github.com/boltdb/bolt"
)

// 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)
}

srcDb, err := v1.Open(source, dbFileMode, &v1.Options{
ReadOnly: true,
Timeout: 1 * time.Minute,
})
if err != nil {
return nil, fmt.Errorf("failed opening source database: %v", err)
}

//Start a connection to the source
srctx, err := srcDb.Begin(false)
if err != nil {
return nil, fmt.Errorf("failed connecting to source database: %v", err)
}
defer srctx.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
desttx, err := destDb.conn.Begin(true)
if err != nil {
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
buckets := [][]byte{dbConf, dbLogs}
for _, b := range buckets {
srcB := srctx.Bucket(b)
destB := desttx.Bucket(b)
err = srcB.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)
}
}

//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 destDb, nil

}
10 changes: 10 additions & 0 deletions v2/bolt_migrate_nobolt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//go:build (!386 && !amd64 && !arm && !arm64 && !ppc && !ppc64 && !ppc64le && !s390x) || nobolt
// +build !386,!amd64,!arm,!arm64,!ppc,!ppc64,!ppc64le,!s390x nobolt

package raftboltdb

// 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) {
return nil, ErrNotImplemented
}
71 changes: 71 additions & 0 deletions v2/bolt_migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//go:build (386 || amd64 || arm || arm64 || ppc || ppc64 || ppc64le || s390x) && !nobolt
// +build 386 amd64 arm arm64 ppc ppc64 ppc64le s390x
// +build !nobolt

package raftboltdb

import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/hashicorp/raft"
v1 "github.com/hashicorp/raft-boltdb"
)

func TestBoltStore_MigrateToV2(t *testing.T) {

dir, err := ioutil.TempDir("", t.Name())
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)

srcFile := filepath.Join(dir, "/sourcepath")
destFile := filepath.Join(dir, "/destpath")

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

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

//Store logs source
if err := srcDb.StoreLogs(logs); err != nil {
t.Fatalf("failed storing logs in source database: %s", err)
}
srcResult := new(raft.Log)
if err := srcDb.GetLog(2, srcResult); err != nil {
t.Fatalf("failed getting log from source database: %s", err)
}

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

destDb, err := MigrateToV2(srcFile, destFile)
if err != nil {
t.Fatalf("did not migrate successfully, err %v", err)
}
defer destDb.Close()

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

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

}
69 changes: 2 additions & 67 deletions v2/bolt_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package raftboltdb

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

metrics "github.com/armon/go-metrics"
v1 "github.com/boltdb/bolt"
"github.com/hashicorp/raft"
"go.etcd.io/bbolt"
)
Expand All @@ -25,6 +22,8 @@ var (

// An error indicating a given key does not exist
ErrKeyNotFound = errors.New("not found")
// An error indicating a feature isn't implemented on the current platform
ErrNotImplemented = errors.New("not implemented")
)

// BoltStore provides access to Bbolt for Raft to store and retrieve
Expand Down Expand Up @@ -297,67 +296,3 @@ func (b *BoltStore) GetUint64(key []byte) (uint64, error) {
func (b *BoltStore) Sync() error {
return b.conn.Sync()
}

// 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)
}

srcDb, err := v1.Open(source, dbFileMode, &v1.Options{
ReadOnly: true,
Timeout: 1 * time.Minute,
})
if err != nil {
return nil, fmt.Errorf("failed opening source database: %v", err)
}

//Start a connection to the source
srctx, err := srcDb.Begin(false)
if err != nil {
return nil, fmt.Errorf("failed connecting to source database: %v", err)
}
defer srctx.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
desttx, err := destDb.conn.Begin(true)
if err != nil {
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
buckets := [][]byte{dbConf, dbLogs}
for _, b := range buckets {
srcB := srctx.Bucket(b)
destB := desttx.Bucket(b)
err = srcB.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)
}
}

//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 destDb, nil

}
57 changes: 0 additions & 57 deletions v2/bolt_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"time"

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

Expand Down Expand Up @@ -416,58 +414,3 @@ func TestBoltStore_SetUint64_GetUint64(t *testing.T) {
t.Fatalf("bad: %v", val)
}
}

func TestBoltStore_MigrateToV2(t *testing.T) {

dir, err := ioutil.TempDir("", t.Name())
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)

srcFile := filepath.Join(dir, "/sourcepath")
destFile := filepath.Join(dir, "/destpath")

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

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

//Store logs source
if err := srcDb.StoreLogs(logs); err != nil {
t.Fatalf("failed storing logs in source database: %s", err)
}
srcResult := new(raft.Log)
if err := srcDb.GetLog(2, srcResult); err != nil {
t.Fatalf("failed getting log from source database: %s", err)
}

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

destDb, err := MigrateToV2(srcFile, destFile)
if err != nil {
t.Fatalf("did not migrate successfully, err %v", err)
}
defer destDb.Close()

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

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

}