package storage
|
|
|
|
|
|
import "os"
|
|
import "fmt"
|
|
import "path/filepath"
|
|
import "encoding/binary"
|
|
|
|
import "github.com/romana/rlog"
|
|
import bolt "github.com/coreos/bbolt"
|
|
import log "github.com/sirupsen/logrus"
|
|
|
|
import "github.com/deroproject/derosuite/globals"
|
|
|
|
type BoltStore struct {
|
|
DB *bolt.DB
|
|
}
|
|
|
|
var Bolt_backend *BoltStore = &BoltStore{} // global variable
|
|
var logger *log.Entry
|
|
|
|
func (b *BoltStore) Init(params map[string]interface{}) (err error) {
|
|
logger = globals.Logger.WithFields(log.Fields{"com": "STORE"})
|
|
current_path := filepath.Join(os.TempDir(), "derod_database.db")
|
|
logger.Infof("Initializing boltdb store at path %s", current_path)
|
|
|
|
// Open the my.db data file in your current directory.
|
|
// It will be created if it doesn't exist.
|
|
b.DB, err = bolt.Open(current_path, 0600, nil)
|
|
if err != nil {
|
|
logger.Fatalf("Cannot open boltdb store err %s\n", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BoltStore) Shutdown() (err error) {
|
|
logger.Infof("Shutting boltdb store")
|
|
if b.DB != nil {
|
|
b.DB.Close()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BoltStore) StoreObject(universe_name []byte, galaxy_name []byte, solar_name []byte, key []byte, data []byte) (err error) {
|
|
rlog.Tracef(10, "Storing object %s %s %x data len %d\n", string(universe_name), string(galaxy_name), key, len(data))
|
|
// open universe bucket
|
|
err = b.DB.Update(func(tx *bolt.Tx) error {
|
|
universe, err := tx.CreateBucketIfNotExists(universe_name)
|
|
if err != nil {
|
|
logger.Errorf("Error while creating universe bucket %s\n", err)
|
|
return err
|
|
}
|
|
galaxy, err := universe.CreateBucketIfNotExists(galaxy_name)
|
|
if err != nil {
|
|
logger.Errorf("Error while creating galaxy bucket %s err\n", string(galaxy_name), err)
|
|
return err
|
|
}
|
|
|
|
solar, err := galaxy.CreateBucketIfNotExists(solar_name)
|
|
if err != nil {
|
|
logger.Errorf("Error while creating solar bucket %s err\n", string(solar_name), err)
|
|
return err
|
|
}
|
|
// now lets update the object attribute
|
|
err = solar.Put(key, data)
|
|
|
|
return err
|
|
})
|
|
return
|
|
|
|
}
|
|
|
|
func (b *BoltStore) LoadObject(universe []byte, bucket_name []byte, solar_bucket []byte, key []byte) (data []byte, err error) {
|
|
rlog.Tracef(10, "Loading object %s %s %x\n", string(universe), string(bucket_name), key)
|
|
// open universe bucket
|
|
err = b.DB.View(func(tx *bolt.Tx) error {
|
|
universe := tx.Bucket(universe)
|
|
if universe == nil {
|
|
return fmt.Errorf("No Such Universe %x\n", universe)
|
|
}
|
|
bucket := universe.Bucket(bucket_name)
|
|
if bucket == nil {
|
|
return fmt.Errorf("No Such Bucket %x\n", bucket_name)
|
|
}
|
|
|
|
solar := bucket.Bucket(solar_bucket)
|
|
if solar == nil {
|
|
return fmt.Errorf("No Such Bucket %x\n", solar)
|
|
}
|
|
|
|
// now lets find the object
|
|
value := solar.Get(key)
|
|
|
|
data = make([]byte, len(value), len(value))
|
|
|
|
copy(data, value) // job done
|
|
|
|
return nil
|
|
})
|
|
return
|
|
}
|
|
|
|
// this function stores a uint64
|
|
func (b *BoltStore) StoreUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte, data uint64) error {
|
|
return b.StoreObject(universe_bucket, galaxy_bucket, solar_bucket, key, itob(data))
|
|
|
|
}
|
|
|
|
// this function loads the data as 64 byte integer
|
|
func (b *BoltStore) LoadUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte) (uint64, error) {
|
|
object_data, err := b.LoadObject(universe_bucket, galaxy_bucket, solar_bucket, key)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if len(object_data) == 0 {
|
|
return 0, fmt.Errorf("No value stored here, we should look more")
|
|
}
|
|
|
|
if len(object_data) != 8 {
|
|
panic("Database corruption, invalid data ")
|
|
}
|
|
|
|
value := binary.BigEndian.Uint64(object_data)
|
|
return value, nil
|
|
}
|
|
|
|
// itob returns an 8-byte big endian representation of v.
|
|
func itob(v uint64) []byte {
|
|
b := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(b, uint64(v))
|
|
return b
|
|
}
|