github.com/igggame/nebulas-go@v2.1.0+incompatible/storage/disk_storage.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package storage 20 21 import ( 22 "sync" 23 24 "github.com/nebulasio/go-nebulas/util/byteutils" 25 26 "github.com/syndtr/goleveldb/leveldb" 27 "github.com/syndtr/goleveldb/leveldb/filter" 28 "github.com/syndtr/goleveldb/leveldb/opt" 29 ) 30 31 // DiskStorage the nodes in trie. 32 type DiskStorage struct { 33 db *leveldb.DB 34 enableBatch bool 35 mutex sync.Mutex 36 batchOpts map[string]*batchOpt 37 } 38 39 type batchOpt struct { 40 key []byte 41 value []byte 42 deleted bool 43 } 44 45 // NewDiskStorage init a storage 46 func NewDiskStorage(path string) (*DiskStorage, error) { 47 db, err := leveldb.OpenFile(path, &opt.Options{ 48 OpenFilesCacheCapacity: 500, 49 BlockCacheCapacity: 8 * opt.MiB, 50 BlockSize: 4 * opt.MiB, 51 Filter: filter.NewBloomFilter(10), 52 }) 53 54 if err != nil { 55 return nil, err 56 } 57 58 return &DiskStorage{ 59 db: db, 60 enableBatch: false, 61 batchOpts: make(map[string]*batchOpt), 62 }, nil 63 } 64 65 // Get return value to the key in Storage 66 func (storage *DiskStorage) Get(key []byte) ([]byte, error) { 67 // if storage.enableBatch { 68 // storage.mutex.Lock() 69 // defer storage.mutex.Unlock() 70 71 // opt := storage.batchOpts[byteutils.Hex(key)] 72 // if opt != nil { 73 // if opt.deleted { 74 // return nil, ErrKeyNotFound 75 // } 76 // return opt.value, nil 77 // } 78 // } 79 80 value, err := storage.db.Get(key, nil) 81 if err != nil && err == leveldb.ErrNotFound { 82 return nil, ErrKeyNotFound 83 } 84 85 return value, err 86 } 87 88 // Put put the key-value entry to Storage 89 func (storage *DiskStorage) Put(key []byte, value []byte) error { 90 if storage.enableBatch { 91 storage.mutex.Lock() 92 defer storage.mutex.Unlock() 93 94 storage.batchOpts[byteutils.Hex(key)] = &batchOpt{ 95 key: key, 96 value: value, 97 deleted: false, 98 } 99 100 return nil 101 } 102 103 return storage.db.Put(key, value, nil) 104 } 105 106 // Del delete the key in Storage. 107 func (storage *DiskStorage) Del(key []byte) error { 108 if storage.enableBatch { 109 storage.mutex.Lock() 110 defer storage.mutex.Unlock() 111 112 storage.batchOpts[byteutils.Hex(key)] = &batchOpt{ 113 key: key, 114 deleted: true, 115 } 116 117 return nil 118 } 119 120 return storage.db.Delete(key, nil) 121 } 122 123 // Close levelDB 124 func (storage *DiskStorage) Close() error { 125 return storage.db.Close() 126 } 127 128 // EnableBatch enable batch write. 129 func (storage *DiskStorage) EnableBatch() { 130 storage.enableBatch = true 131 } 132 133 // Flush write and flush pending batch write. 134 func (storage *DiskStorage) Flush() error { 135 storage.mutex.Lock() 136 defer storage.mutex.Unlock() 137 138 if !storage.enableBatch { 139 return nil 140 } 141 142 batch := new(leveldb.Batch) 143 for _, opt := range storage.batchOpts { 144 if opt.deleted { 145 batch.Delete(opt.key) 146 } else { 147 batch.Put(opt.key, opt.value) 148 } 149 } 150 storage.batchOpts = make(map[string]*batchOpt) 151 152 return storage.db.Write(batch, nil) 153 } 154 155 // DisableBatch disable batch write. 156 func (storage *DiskStorage) DisableBatch() { 157 storage.mutex.Lock() 158 defer storage.mutex.Unlock() 159 160 storage.batchOpts = make(map[string]*batchOpt) 161 storage.enableBatch = false 162 }