github.com/turingchain2020/turingchain@v1.1.21/common/db/go_ssdb.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package db 6 7 import ( 8 "bytes" 9 10 log "github.com/turingchain2020/turingchain/common/log/log15" 11 "github.com/syndtr/goleveldb/leveldb/util" 12 13 "fmt" 14 "strconv" 15 "strings" 16 "time" 17 18 "github.com/turingchain2020/turingchain/types" 19 ) 20 21 var dlog = log.New("module", "db.ssdb") 22 var sdbBench = &SsdbBench{} 23 24 func init() { 25 dbCreator := func(name string, dir string, cache int) (DB, error) { 26 return NewGoSSDB(name, dir, cache) 27 } 28 registerDBCreator(ssDBBackendStr, dbCreator, false) 29 } 30 31 //SsdbBench ... 32 type SsdbBench struct { 33 // 写次数 34 writeCount int 35 // 写条数 36 writeNum int 37 // 写耗费时间 38 writeTime time.Duration 39 readCount int 40 readNum int 41 readTime time.Duration 42 } 43 44 //SsdbNode 节点 45 type SsdbNode struct { 46 ip string 47 port int 48 } 49 50 //GoSSDB db 51 type GoSSDB struct { 52 BaseDB 53 pool *SDBPool 54 nodes []*SsdbNode 55 } 56 57 func (bench *SsdbBench) write(num int, cost time.Duration) { 58 bench.writeCount++ 59 bench.writeNum += num 60 bench.writeTime += cost 61 } 62 63 func (bench *SsdbBench) read(num int, cost time.Duration) { 64 bench.readCount++ 65 bench.readNum += num 66 bench.readTime += cost 67 } 68 69 func (bench *SsdbBench) String() string { 70 return fmt.Sprintf("SSDBBenchmark[(ReadTimes=%v, ReadRecordNum=%v, ReadCostTime=%v;) (WriteTimes=%v, WriteRecordNum=%v, WriteCostTime=%v)", 71 bench.readCount, bench.readNum, bench.readTime, bench.writeCount, bench.writeNum, bench.writeTime) 72 } 73 74 func printSsdbBenchmark() { 75 tick := time.Tick(time.Minute * 5) 76 for { 77 <-tick 78 dlog.Info(sdbBench.String()) 79 } 80 } 81 82 // url pattern: ip:port,ip:port 83 func parseSsdbNode(url string) (nodes []*SsdbNode) { 84 hosts := strings.Split(url, ",") 85 if hosts == nil { 86 dlog.Error("invalid ssdb url") 87 return nil 88 } 89 for _, host := range hosts { 90 parts := strings.Split(host, ":") 91 if parts == nil || len(parts) != 2 { 92 dlog.Error("invalid ssd url", "part", host) 93 continue 94 } 95 ip := parts[0] 96 port, err := strconv.Atoi(parts[1]) 97 if err != nil { 98 dlog.Error("invalid ssd url host port", "port", parts[1]) 99 continue 100 } 101 nodes = append(nodes, &SsdbNode{ip, port}) 102 } 103 return nodes 104 } 105 106 //NewGoSSDB new 107 func NewGoSSDB(name string, dir string, cache int) (*GoSSDB, error) { 108 database := &GoSSDB{} 109 database.nodes = parseSsdbNode(dir) 110 111 if database.nodes == nil { 112 dlog.Error("no valid ssdb instance exists, exit!") 113 return nil, types.ErrDataBaseDamage 114 } 115 var err error 116 database.pool, err = NewSDBPool(database.nodes) 117 if err != nil { 118 dlog.Error("connect to ssdb error!", "ssdb", database.nodes[0]) 119 return nil, types.ErrDataBaseDamage 120 } 121 122 go printSsdbBenchmark() 123 124 return database, nil 125 } 126 127 //Get get 128 func (db *GoSSDB) Get(key []byte) ([]byte, error) { 129 start := time.Now() 130 131 value, err := db.pool.get().Get(string(key)) 132 if err != nil { 133 //dlog.Error("Get value error", "error", err, "key", key, "keyhex", hex.EncodeToString(key), "keystr", string(key)) 134 return nil, err 135 } 136 if value == nil { 137 return nil, ErrNotFoundInDb 138 } 139 140 sdbBench.read(1, time.Since(start)) 141 return value.Bytes(), nil 142 } 143 144 //Set 设置 145 func (db *GoSSDB) Set(key []byte, value []byte) error { 146 start := time.Now() 147 148 err := db.pool.get().Set(string(key), value) 149 if err != nil { 150 dlog.Error("Set", "error", err) 151 return err 152 } 153 sdbBench.write(1, time.Since(start)) 154 return nil 155 } 156 157 //SetSync 同步 158 func (db *GoSSDB) SetSync(key []byte, value []byte) error { 159 return db.Set(key, value) 160 } 161 162 //Delete 删除 163 func (db *GoSSDB) Delete(key []byte) error { 164 start := time.Now() 165 166 err := db.pool.get().Del(string(key)) 167 if err != nil { 168 dlog.Error("Delete", "error", err) 169 return err 170 } 171 sdbBench.write(1, time.Since(start)) 172 return nil 173 } 174 175 //DeleteSync 删除同步 176 func (db *GoSSDB) DeleteSync(key []byte) error { 177 return db.Delete(key) 178 } 179 180 //Close 关闭 181 func (db *GoSSDB) Close() { 182 db.pool.close() 183 } 184 185 //Print 打印 186 func (db *GoSSDB) Print() { 187 } 188 189 //Stats ... 190 func (db *GoSSDB) Stats() map[string]string { 191 return make(map[string]string) 192 } 193 194 //Iterator 迭代器 195 func (db *GoSSDB) Iterator(itbeg []byte, itend []byte, reverse bool) Iterator { 196 start := time.Now() 197 198 var ( 199 keys []string 200 err error 201 begin string 202 end string 203 ) 204 if itend == nil { 205 itend = bytesPrefix(itbeg) 206 } 207 if bytes.Equal(itend, types.EmptyValue) { 208 itend = nil 209 } 210 limit := util.Range{Start: itbeg, Limit: itend} 211 if reverse { 212 begin = string(limit.Limit) 213 end = string(itbeg) 214 keys, err = db.pool.get().Rkeys(begin, end, IteratorPageSize) 215 } else { 216 begin = string(itbeg) 217 end = string(limit.Limit) 218 keys, err = db.pool.get().Keys(begin, end, IteratorPageSize) 219 } 220 221 it := newSSDBIt(begin, end, itbeg, itend, []string{}, reverse, db) 222 if err != nil { 223 dlog.Error("get iterator error", "error", err, "keys", keys) 224 return it 225 } 226 if len(keys) > 0 { 227 it.keys = keys 228 229 // 如果返回的数据大小刚好满足分页,则假设下一页还有数据 230 if len(it.keys) == IteratorPageSize { 231 it.nextPage = true 232 it.tmpEnd = it.keys[IteratorPageSize-1] 233 } 234 } 235 236 sdbBench.read(len(keys), time.Since(start)) 237 return it 238 } 239 240 // 因为ssdb不支持原生的迭代器模式,需要一次获取KEY; 241 // 为了防止匹配的KEY范围过大,这里需要进行分页,每次只取1024条KEY; 242 // Next方法自动进行跨页取数据 243 type ssDBIt struct { 244 itBase 245 db *GoSSDB 246 keys []string 247 index int 248 reverse bool 249 // 迭代开始位置 250 begin string 251 // 迭代结束位置 252 end string 253 254 // 需要分页的情况下,下一页的开始位置 255 // 是否有下一页数据 256 tmpEnd string 257 nextPage bool 258 259 // 当前所属的页数(从0开始) 260 pageNo int 261 } 262 263 func newSSDBIt(begin, end string, prefix, itend []byte, keys []string, reverse bool, db *GoSSDB) *ssDBIt { 264 return &ssDBIt{ 265 itBase: itBase{prefix, itend, reverse}, 266 index: -1, 267 keys: keys, 268 reverse: reverse, 269 db: db, 270 } 271 } 272 273 func (dbit *ssDBIt) Close() { 274 dbit.keys = []string{} 275 } 276 277 // 获取下一页的数据 278 func (dbit *ssDBIt) cacheNextPage(begin string) bool { 279 if dbit.initKeys(begin, dbit.end) { 280 dbit.index = 0 281 dbit.pageNo++ 282 return true 283 } 284 return false 285 286 } 287 288 func (dbit *ssDBIt) initKeys(begin, end string) bool { 289 var ( 290 keys []string 291 err error 292 ) 293 if dbit.reverse { 294 keys, err = dbit.db.pool.get().Rkeys(begin, end, IteratorPageSize) 295 } else { 296 keys, err = dbit.db.pool.get().Keys(begin, end, IteratorPageSize) 297 } 298 if err != nil { 299 dlog.Error("get iterator next page error", "error", err, "begin", begin, "end", dbit.end, "reverse", dbit.reverse) 300 return false 301 } 302 303 if len(keys) > 0 { 304 // 这里只改变keys,不改变index 305 dbit.keys = keys 306 307 // 如果返回的数据大小刚好满足分页,则假设下一页还有数据 308 if len(keys) == IteratorPageSize { 309 dbit.nextPage = true 310 dbit.tmpEnd = dbit.keys[IteratorPageSize-1] 311 } else { 312 dbit.nextPage = false 313 } 314 return true 315 } 316 return false 317 318 } 319 320 func (dbit *ssDBIt) Next() bool { 321 if len(dbit.keys) > dbit.index+1 { 322 dbit.index++ 323 return true 324 } 325 // 如果有下一页数据,则自动抓取 326 if dbit.nextPage { 327 return dbit.cacheNextPage(dbit.tmpEnd) 328 } 329 return false 330 331 } 332 333 func (dbit *ssDBIt) checkKeyCmp(key1, key2 string, reverse bool) bool { 334 if reverse { 335 return strings.Compare(key1, key2) < 0 336 } 337 return strings.Compare(key1, key2) > 0 338 } 339 340 func (dbit *ssDBIt) findInPage(key string) int { 341 pos := -1 342 for i, v := range dbit.keys { 343 if i < dbit.index { 344 continue 345 } 346 if dbit.checkKeyCmp(key, v, dbit.reverse) { 347 continue 348 } else { 349 pos = i 350 break 351 } 352 } 353 return pos 354 } 355 356 func (dbit *ssDBIt) Seek(key []byte) bool { 357 keyStr := string(key) 358 pos := dbit.findInPage(keyStr) 359 360 // 如果第一页已经找到,不会走入此逻辑 361 for pos == -1 && dbit.nextPage { 362 if dbit.cacheNextPage(dbit.tmpEnd) { 363 pos = dbit.findInPage(keyStr) 364 } else { 365 break 366 } 367 } 368 369 dbit.index = pos 370 return dbit.Valid() 371 } 372 373 func (dbit *ssDBIt) Rewind() bool { 374 // 目前代码的Rewind调用都是在第一页,正常情况下走不到else分支; 375 // 但为了代码健壮性考虑,这里增加对else分支的处理 376 if dbit.pageNo == 0 { 377 dbit.index = 0 378 return true 379 } 380 381 // 当数据取到第N页的情况时,Rewind需要返回到第一页第一条 382 if dbit.initKeys(dbit.begin, dbit.end) { 383 dbit.index = 0 384 dbit.pageNo = 0 385 return true 386 } 387 return false 388 389 } 390 391 func (dbit *ssDBIt) Key() []byte { 392 if dbit.index >= 0 && dbit.index < len(dbit.keys) { 393 return []byte(dbit.keys[dbit.index]) 394 } 395 return nil 396 397 } 398 func (dbit *ssDBIt) Value() []byte { 399 key := dbit.keys[dbit.index] 400 value, err := dbit.db.Get([]byte(key)) 401 402 if err != nil { 403 dlog.Error("get iterator value error", "key", key, "error", err) 404 return nil 405 } 406 return value 407 } 408 409 func (dbit *ssDBIt) Error() error { 410 return nil 411 } 412 413 func (dbit *ssDBIt) ValueCopy() []byte { 414 v := dbit.Value() 415 value := make([]byte, len(v)) 416 copy(value, v) 417 return value 418 } 419 420 func (dbit *ssDBIt) Valid() bool { 421 start := time.Now() 422 if dbit.index < 0 { 423 return false 424 } 425 if len(dbit.keys) <= dbit.index { 426 return false 427 } 428 key := dbit.keys[dbit.index] 429 sdbBench.read(1, time.Since(start)) 430 return dbit.checkKey([]byte(key)) 431 } 432 433 type ssDBBatch struct { 434 db *GoSSDB 435 batchset map[string][]byte 436 batchdel map[string]bool 437 size int 438 } 439 440 //NewBatch new 441 func (db *GoSSDB) NewBatch(sync bool) Batch { 442 return &ssDBBatch{db: db, batchset: make(map[string][]byte), batchdel: make(map[string]bool)} 443 } 444 445 func (db *ssDBBatch) Set(key, value []byte) { 446 db.batchset[string(key)] = value 447 delete(db.batchdel, string(key)) 448 db.size += len(value) 449 db.size += len(key) 450 } 451 452 func (db *ssDBBatch) Delete(key []byte) { 453 db.batchset[string(key)] = []byte{} 454 delete(db.batchset, string(key)) 455 db.batchdel[string(key)] = true 456 db.size += len(key) 457 } 458 459 // 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作; 460 // 所以这里先执行更新操作(删除的KEY在这里会将VALUE设置为空); 461 // 然后再执行删除操作; 462 // 这样即使中间执行出错,也不会导致删除结果未写入的情况(值已经被置空); 463 func (db *ssDBBatch) Write() error { 464 start := time.Now() 465 466 if len(db.batchset) > 0 { 467 err := db.db.pool.get().MultiSet(db.batchset) 468 if err != nil { 469 dlog.Error("Write (multi_set)", "error", err) 470 return err 471 } 472 } 473 474 if len(db.batchdel) > 0 { 475 var dkeys []string 476 for k := range db.batchdel { 477 dkeys = append(dkeys, k) 478 } 479 err := db.db.pool.get().MultiDel(dkeys...) 480 if err != nil { 481 dlog.Error("Write (multi_del)", "error", err) 482 return err 483 } 484 } 485 486 sdbBench.write(len(db.batchset)+len(db.batchdel), time.Since(start)) 487 return nil 488 } 489 490 func (db *ssDBBatch) ValueSize() int { 491 return db.size 492 } 493 494 //ValueLen batch数量 495 func (db *ssDBBatch) ValueLen() int { 496 return len(db.batchset) 497 } 498 499 func (db *ssDBBatch) Reset() { 500 db.batchset = make(map[string][]byte) 501 db.batchdel = make(map[string]bool) 502 db.size = 0 503 } 504 505 func (db *ssDBBatch) UpdateWriteSync(sync bool) { 506 }