github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/data/kv/kv-badger-db.go (about) 1 package kv 2 3 import ( 4 "github.com/angenalZZZ/gofunc/f" 5 "github.com/dgraph-io/badger/v2" 6 "github.com/dgraph-io/badger/v2/options" 7 "strconv" 8 "time" 9 ) 10 11 /** 12 * Feature 键值功能设计 https://github.com/dgraph-io/badger 13 * Design 数据结构设计 LSM tree with value log, it's not a B+ tree 14 * High Read throughput 高读取吞吐量 Yes 15 * High Write throughput 高写入吞吐量 Yes 16 * Designed for SSDs 专为固态硬盘设计 Yes (with latest research 1) 17 * Embeddable 可嵌入 Yes 18 * Sorted KV access 排序KV访问 Yes 19 * Transactions 事务管理 Yes, concurrent with SSI3, ACID: 原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability 20 * Snapshots 快照 Yes 21 * TTL support 过期支持 Yes 22 * 3D access (key-value-version) 3D访问(键值版本)Yes 23 */ 24 type BadgerDB struct { 25 DB *badger.DB 26 locker *f.Locker 27 } 28 29 // Open BadgerDB represents a badger db implementation, 30 // or no path, db save in memory. 31 func (db *BadgerDB) Open(path ...string) error { 32 var opt badger.Options 33 if len(path) == 1 { 34 opt = badger.DefaultOptions(path[0]) 35 opt.Truncate = true 36 opt.SyncWrites = false 37 opt.TableLoadingMode = options.MemoryMap 38 opt.ValueLogLoadingMode = options.FileIO 39 //opt.ValueThreshold = 1 << 20 // 阈值 1 MB 40 opt.ValueThreshold = 1 // 阈值 默认 32 41 opt.NumMemtables = 2 42 opt.NumLevelZeroTables = 2 43 opt.MaxTableSize = 16 << 20 44 } else { 45 opt = badger.DefaultOptions("").WithInMemory(true) 46 } 47 48 _db, err := badger.Open(opt) 49 if err != nil { 50 return err 51 } 52 53 db.DB = _db 54 db.locker = f.NewLocker() 55 if opt.InMemory { 56 return nil 57 } 58 59 go (func() { 60 for db.DB.RunValueLogGC(0.5) == nil { 61 // cleaning ... 62 } 63 })() 64 return nil 65 } 66 67 // Size gets the size of the database (LSM + ValueLog) in bytes. 68 func (db *BadgerDB) Size() int64 { 69 lsm, vLog := db.DB.Size() 70 return lsm + vLog 71 } 72 73 // Incr - increment the key by the specified value. 74 func (db *BadgerDB) Incr(k string, by int64) (int64, error) { 75 db.locker.Lock(k) 76 defer db.locker.Unlock(k) 77 78 val, err := db.Get(k) 79 if err != nil || val == "" { 80 val = "0" 81 } 82 83 valFloat, _ := strconv.ParseInt(val, 10, 64) 84 valFloat += by 85 86 err = db.Set(k, strconv.FormatInt(valFloat, 10), -1) 87 if err != nil { 88 return 0, err 89 } 90 91 return valFloat, nil 92 } 93 94 // Set sets a key with the specified value and optional ttl.seconds 95 func (db *BadgerDB) Set(k, v string, ttl int) error { 96 return db.SetBytes(f.Bytes(k), f.Bytes(v), ttl) 97 } 98 99 // SetBytes sets a key with the specified value and optional ttl.seconds 100 func (db *BadgerDB) SetBytes(k, v []byte, ttl int) error { 101 return db.DB.Update(func(txn *badger.Txn) (err error) { 102 if ttl <= 0 { 103 err = txn.Set(k, v) 104 } else { 105 err = txn.SetEntry(&badger.Entry{ 106 Key: k, 107 Value: v, 108 ExpiresAt: uint64(time.Now().Add(time.Duration(ttl) * time.Second).Unix()), 109 }) 110 } 111 return err 112 }) 113 } 114 115 // MSet sets multiple key-value pairs. 116 func (db *BadgerDB) MSet(data map[string]string) error { 117 return db.DB.Update(func(txn *badger.Txn) error { 118 for k, v := range data { 119 if err := txn.Set(f.Bytes(k), f.Bytes(v)); err != nil { 120 return err 121 } 122 } 123 return nil 124 }) 125 } 126 127 // Get fetches the value of the specified k. 128 func (db *BadgerDB) Get(k string) (string, error) { 129 data, err := db.GetBytes(f.Bytes(k)) 130 if err != nil { 131 return "", err 132 } 133 return f.String(data), nil 134 } 135 136 // GetBytes fetches the value of the specified k. 137 func (db *BadgerDB) GetBytes(k []byte) ([]byte, error) { 138 var data []byte 139 err := db.DB.View(func(txn *badger.Txn) error { 140 item, err := txn.Get(k) 141 if err != nil { 142 return err 143 } 144 145 data, err = item.ValueCopy(nil) 146 return err 147 }) 148 return data, err 149 } 150 151 // MGet fetch multiple values of the specified keys. 152 func (db *BadgerDB) MGet(keys []string) (data []string) { 153 data = make([]string, 0, len(keys)) 154 _ = db.DB.View(func(txn *badger.Txn) error { 155 for _, key := range keys { 156 item, err := txn.Get(f.Bytes(key)) 157 if err != nil { 158 data = append(data, "") 159 continue 160 } 161 val, err := item.ValueCopy(nil) 162 if err != nil { 163 data = append(data, "") 164 continue 165 } 166 data = append(data, f.String(val)) 167 } 168 return nil 169 }) 170 return data 171 } 172 173 // TTL gets the time.seconds to live of the specified key's value. 174 func (db *BadgerDB) TTL(key string) int64 { 175 var expires int64 176 177 _ = db.DB.View(func(txn *badger.Txn) error { 178 item, err := txn.Get(f.Bytes(key)) 179 if err != nil { 180 expires = -2 181 return nil 182 } 183 184 exp := item.ExpiresAt() 185 if exp == 0 { 186 expires = -1 187 return nil 188 } 189 190 expires = int64(exp) 191 return nil 192 }) 193 194 if expires == -2 { 195 return -2 196 } 197 198 if expires == -1 { 199 return -1 200 } 201 202 now := time.Now().Unix() 203 204 if now >= expires { 205 return -2 206 } 207 208 return (expires - now) / int64(time.Second) 209 } 210 211 // Del removes key(s) from the store. 212 func (db *BadgerDB) Del(keys []string) error { 213 return db.DB.Update(func(txn *badger.Txn) error { 214 for _, key := range keys { 215 if err := txn.Delete(f.Bytes(key)); err != nil { 216 return err 217 } 218 } 219 return nil 220 }) 221 } 222 223 // Close ... 224 func (db *BadgerDB) Close() error { 225 return db.DB.Close() 226 } 227 228 // Keys gets matched keys. 229 func (db *BadgerDB) Keys(prefix ...string) []string { 230 opts := badger.DefaultIteratorOptions 231 opts.PrefetchValues = false 232 var prefixBytes []byte 233 var keys []string 234 l := len(prefix) 235 if l > 0 { 236 prefixBytes = f.Bytes(prefix[0]) 237 } 238 _ = db.DB.View(func(txn *badger.Txn) error { 239 it := txn.NewIterator(opts) 240 defer it.Close() 241 if l == 0 { 242 for it.Rewind(); it.Valid(); it.Next() { 243 keys = append(keys, f.String(it.Item().Key())) 244 } 245 } else { 246 for it.Seek(prefixBytes); it.ValidForPrefix(prefixBytes); it.Next() { 247 keys = append(keys, f.String(it.Item().Key())) 248 } 249 } 250 return nil 251 }) 252 return keys 253 } 254 255 // GC runs the garbage collector, not in memory. 256 func (db *BadgerDB) GC() error { 257 var err error 258 for { 259 err = db.DB.RunValueLogGC(0.5) 260 if err != nil { 261 break 262 } 263 } 264 return err 265 }