github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/storage/badgerdb.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 // 64 bit arch will use this DB 18 19 package storage 20 21 import "os" 22 import "fmt" 23 import "sync" 24 import "runtime" 25 import "path/filepath" 26 import "encoding/binary" 27 28 //import "github.com/romana/rlog" 29 //import bolt "github.com/coreos/bbolt" 30 import "github.com/dgraph-io/badger" 31 import log "github.com/sirupsen/logrus" 32 import "github.com/dgraph-io/badger/options" 33 34 import "github.com/deroproject/derosuite/globals" 35 36 type BadgerDBStore struct { 37 DB *badger.DB 38 sync.Mutex // lock this struct TODO we must user a reader lock 39 } 40 41 // this object is returned 42 type BadgerTXWrapper struct { 43 bdb *BadgerDBStore 44 tx *badger.Txn 45 } 46 47 var Badger_backend *BadgerDBStore = &BadgerDBStore{} // global variable 48 49 func (b *BadgerDBStore) Init(params map[string]interface{}) (err error) { 50 logger = globals.Logger.WithFields(log.Fields{"com": "STORE"}) 51 current_path := filepath.Join(globals.GetDataDirectory(), "derod_badger_database") 52 53 if params["--simulator"] == true { 54 current_path = filepath.Join(os.TempDir(), "derod_simulation_badger_database") // sp 55 } 56 logger.Infof("Initializing badger store at path %s", current_path) 57 58 // Open the my.db data file in your current directory. 59 // It will be created if it doesn't exist. 60 61 opts := badger.DefaultOptions 62 opts.Dir = current_path 63 opts.ValueDir = current_path 64 65 // tune to different RAM requirements based on arch 66 if runtime.GOARCH == "amd64" { 67 opts.TableLoadingMode = options.MemoryMap 68 opts.ValueLogLoadingMode = options.MemoryMap 69 } else { // 32 bit systems/arm etc use raw file IO, no memory mapping 70 opts.TableLoadingMode = options.FileIO 71 opts.ValueLogLoadingMode = options.FileIO 72 logger.Infof("Running in low RAM mode") 73 } 74 75 db, err := badger.Open(opts) 76 if err != nil { 77 logger.Fatalf("Cannot open badgerdb store err %s", err) 78 } 79 b.DB = db 80 81 // if simulation, delete the file , so as it gets cleaned up automcatically 82 if params["--simulator"] == true { 83 os.RemoveAll(current_path) 84 } 85 86 // place db in no sync mode 87 //b.DB.NoSync = true 88 89 return nil 90 } 91 92 func (b *BadgerDBStore) Shutdown() (err error) { 93 logger.Infof("Shutting badgerdb store") 94 if b.DB != nil { 95 b.DB.Close() 96 } 97 98 return nil 99 } 100 101 // sync the DB to disk 102 func (b *BadgerDBStore) Sync() { 103 104 } 105 106 // get a new writable/readable tx, 107 // we will manage the writable txs manually 108 // since a block may cause changes to a number of fields which must be reflected atomically 109 func (b *BadgerDBStore) BeginTX(writable bool) (DBTX, error) { 110 111 txwrapper := &BadgerTXWrapper{} 112 tx := b.DB.NewTransaction(writable) // begin a new writable tx 113 txwrapper.tx = tx 114 txwrapper.bdb = b // parent DB reference 115 116 return txwrapper, nil 117 } 118 119 func (b *BadgerTXWrapper) Commit() error { 120 err := b.tx.Commit(nil) 121 if err != nil { 122 logger.Warnf("Error while committing tx, err %s", err) 123 return err 124 } 125 b.tx.Discard() // tx must always be discarded (both if commited/rollback as per documentation) 126 127 return nil 128 } 129 130 // Roll back existing changes to disk 131 func (b *BadgerTXWrapper) Rollback() { 132 133 b.tx.Discard() 134 } 135 136 // TODO implement this 137 func (b *BadgerTXWrapper) Sync() { 138 139 } 140 141 // duplicates a byte array as badger db needs objects which are unmodifieable during the transaction 142 func Duplicate(input []byte) []byte { 143 dup := make([]byte, len(input), len(input)) 144 copy(dup, input) 145 return dup 146 } 147 148 func (b *BadgerTXWrapper) StoreObject(universe_name []byte, galaxy_name []byte, solar_name []byte, key []byte, data []byte) (err error) { 149 fullkey := make([]byte, 0, len(universe_name)+len(galaxy_name)+len(solar_name)+len(key)) 150 151 fullkey = append(fullkey, universe_name...) 152 fullkey = append(fullkey, galaxy_name...) 153 fullkey = append(fullkey, solar_name...) 154 fullkey = append(fullkey, key...) 155 return b.tx.Set(fullkey, Duplicate(data)) 156 157 } 158 159 func (b *BadgerTXWrapper) LoadObject(universe_name []byte, galaxy_name []byte, solar_name []byte, key []byte) (data []byte, err error) { 160 161 fullkey := make([]byte, 0, len(universe_name)+len(galaxy_name)+len(solar_name)+len(key)) 162 163 fullkey = append(fullkey, universe_name...) 164 fullkey = append(fullkey, galaxy_name...) 165 fullkey = append(fullkey, solar_name...) 166 fullkey = append(fullkey, key...) 167 168 item, err := b.tx.Get(fullkey) 169 if err == badger.ErrKeyNotFound { 170 return data, badger.ErrKeyNotFound 171 } 172 data, err = item.ValueCopy(nil) 173 if err != nil { 174 return data, badger.ErrKeyNotFound 175 } 176 return data, nil 177 } 178 179 // this function stores a uint64 180 // this will automcatically use the transaction 181 func (b *BadgerTXWrapper) StoreUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte, data uint64) error { 182 return b.StoreObject(universe_bucket, galaxy_bucket, solar_bucket, key, itob(data)) 183 184 } 185 186 // this function loads the data as 64 byte integer 187 func (b *BadgerTXWrapper) LoadUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte) (uint64, error) { 188 object_data, err := b.LoadObject(universe_bucket, galaxy_bucket, solar_bucket, key) 189 if err != nil { 190 return 0, err 191 } 192 193 if len(object_data) == 0 { 194 return 0, fmt.Errorf("No value stored here, we should look more") 195 } 196 197 if len(object_data) != 8 { 198 panic("Database corruption, invalid data ") 199 } 200 201 value := binary.BigEndian.Uint64(object_data) 202 return value, nil 203 }