github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/others/qdb/db_disk.go (about) 1 // Copyright 2009 The Go Authors. 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 /* 6 Qdb is a fast persistent storage database. 7 8 The records are binary blobs that can have a variable length, up to 4GB. 9 10 The key must be a unique 64-bit value, most likely a hash of the actual key. 11 12 They data is stored on a disk, in a folder specified during the call to NewDB(). 13 There are can be three possible files in that folder 14 * qdb.0, qdb.1 - these files store a compact version of the entire database 15 * qdb.log - this one stores the changes since the most recent qdb.0 or qdb.1 16 17 */ 18 package qdb 19 20 import ( 21 "os" 22 "io" 23 "fmt" 24 "strconv" 25 "path/filepath" 26 "encoding/binary" 27 ) 28 29 30 func (db *DB) seq2fn(seq uint32) string { 31 return fmt.Sprintf("%s%08x.dat", db.Dir, seq) 32 } 33 34 func (db *DB) checklogfile() { 35 // If could not open, create it 36 if db.LogFile == nil { 37 fn := db.seq2fn(db.DataSeq) 38 db.LogFile, _ = os.Create(fn) 39 binary.Write(db.LogFile, binary.LittleEndian, uint32(db.DataSeq)) 40 db.LastValidLogPos = 4 41 } 42 } 43 44 45 // load record from disk, if not loaded yet 46 func (db *DB) loadrec(idx *oneIdx) { 47 if idx.data == nil { 48 var f *os.File 49 if f, _ = db.DatFiles[idx.DataSeq]; f==nil { 50 fn := db.seq2fn(idx.DataSeq) 51 f, _ = os.Open(fn) 52 if f==nil { 53 println("file", fn, "not found") 54 os.Exit(1) 55 } 56 db.DatFiles[idx.DataSeq] = f 57 } 58 idx.LoadData(f) 59 } 60 } 61 62 // add record at the end of the log 63 func (db *DB) addtolog(f io.Writer, key KeyType, val []byte) (fpos int64) { 64 if f==nil { 65 db.checklogfile() 66 db.LogFile.Seek(db.LastValidLogPos, os.SEEK_SET) 67 f = db.LogFile 68 } 69 70 fpos = db.LastValidLogPos 71 f.Write(val) 72 db.LastValidLogPos += int64(len(val)) // 4 bytes for CRC 73 74 return 75 } 76 77 // add record at the end of the log 78 func (db *DB) cleanupold(used map[uint32]bool) { 79 filepath.Walk(db.Dir, func(path string, info os.FileInfo, err error) error { 80 fn := info.Name() 81 if len(fn)==12 && fn[8:12]==".dat" { 82 v, er := strconv.ParseUint(fn[:8], 16, 32) 83 if er == nil && uint32(v)!=db.DataSeq { 84 if _, ok := used[uint32(v)]; !ok { 85 //println("deleting", v, path) 86 if f, _ := db.DatFiles[uint32(v)]; f!=nil { 87 f.Close() 88 delete(db.DatFiles, uint32(v)) 89 } 90 os.Remove(path) 91 } 92 } 93 } 94 return nil 95 }) 96 }