func create(f *os.File, filer lldb.Filer, opts *Options, isMem bool) (db *DB, err error) { defer func() { if db != nil { db.opts = opts } }() defer func() { lock := opts.lock if err != nil && lock != nil { lock.Close() db = nil } }() if err = opts.check(filer.Name(), true, !isMem); err != nil { return } b := [16]byte{byte(magic[0]), byte(magic[1]), byte(magic[2]), byte(magic[3]), 0x00} // ver 0x00 if n, err := filer.WriteAt(b[:], 0); n != 16 { return nil, &os.PathError{Op: "kv.create.WriteAt", Path: filer.Name(), Err: err} } db = &DB{f: f, lock: opts.lock} if filer, err = opts.acidFiler(db, filer); err != nil { return nil, err } db.filer = filer if err = filer.BeginUpdate(); err != nil { return } defer func() { if e := filer.EndUpdate(); e != nil { if err == nil { err = e } } }() if db.alloc, err = lldb.NewAllocator(lldb.NewInnerFiler(filer, 16), &lldb.Options{}); err != nil { return nil, &os.PathError{Op: "kv.create", Path: filer.Name(), Err: err} } db.alloc.Compress = true db.isMem = isMem var h int64 if db.root, h, err = lldb.CreateBTree(db.alloc, opts.Compare); err != nil { return } if h != 1 { panic("internal error") } db.wal = opts.wal return }
func fillseq() { dbname := os.Args[0] + ".db" f, err := os.OpenFile(dbname, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666) if err != nil { log.Fatal(err) } defer func() { f.Close() os.Remove(f.Name()) }() filer := lldb.NewSimpleFileFiler(f) a, err := lldb.NewAllocator(filer, &lldb.Options{}) if err != nil { log.Println(err) return } a.Compress = true b, _, err := lldb.CreateBTree(a, nil) if err != nil { log.Println(err) return } var keys [N][16]byte for i := range keys { binary.BigEndian.PutUint32(keys[i][:], uint32(i)) } debug.FreeOSMemory() t0 := time.Now() for _, key := range keys { if err = b.Set(key[:], value100); err != nil { log.Println(err) return } } if err := filer.Sync(); err != nil { log.Println(err) return } var ms runtime.MemStats runtime.ReadMemStats(&ms) d := time.Since(t0) fi, err := f.Stat() if err != nil { log.Println(err) return } secs := float64(d/time.Nanosecond) / float64(time.Second) sz := fi.Size() fmt.Printf("fillseq :%19v/op;%7.1f MB/s (%g secs, %d bytes)\n", d/N, float64(sz)/secs/1e6, secs, sz) nn, bytes := bufs.GCache.Stats() fmt.Printf("%d %d\n", nn, bytes) fmt.Printf("%+v\n", ms) }
func (t *treeCache) getTree(db *DB, prefix int, name string, canCreate bool, cacheSize int) (r *lldb.BTree, err error) { m := t.get() r, ok := m[name] if ok { return } root, err := db.root() if err != nil { return } val, err := root.get(prefix, name) if err != nil { return } switch x := val.(type) { case nil: if !canCreate { return } var h int64 r, h, err = lldb.CreateBTree(db.alloc, collate) if err != nil { return nil, err } if err = root.set(h, prefix, name); err != nil { return nil, err } case int64: if r, err = lldb.OpenBTree(db.alloc, collate, x); err != nil { return nil, err } default: return nil, &lldb.ErrINVAL{Src: "corrupted root directory value for", Val: fmt.Sprintf("%q, %q", prefix, name)} } if len(m) > cacheSize { i, j, n := 0, cacheSize/2, mathutil.Min(cacheSize/20, 10) loop: for k := range m { if i++; i >= j { delete(m, k) if n == 0 { break loop } n-- } } } m[name] = r return }
func TestProf(t *testing.T) { dbname := os.Args[0] + ".db" f, err := os.OpenFile(dbname, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666) if err != nil { t.Fatal(err) } defer func() { f.Close() os.Remove(f.Name()) }() filer := lldb.NewSimpleFileFiler(f) // file //filer := lldb.NewMemFiler() // mem a, err := lldb.NewAllocator(filer, &lldb.Options{}) if err != nil { t.Error(err) return } a.Compress = true b, _, err := lldb.CreateBTree(a, nil) if err != nil { t.Error(err) return } var key [16]byte for i := uint32(0); int(i) < 1e6; i++ { binary.BigEndian.PutUint32(key[:], i) if err = b.Set(key[:], value100); err != nil { t.Error(err) return } } var ms runtime.MemStats runtime.ReadMemStats(&ms) bufsU, bufsT, bytesU, bytesT, h, m := a.CacheStats() const p = 100.0 t.Logf( "cache: buffers %d/%d(%.1f%%), bytes %d/%d(%.1f%%), hits %d(%.1f%%), misses %d(%.1f%%)", bufsU, bufsT, p*float64(bufsU)/float64(bufsT), bytesU, bytesT, p*float64(bytesU)/float64(bytesT), h, p*float64(h)/float64(h+m), m, p*float64(m)/float64(h+m), ) nn, bts := bufs.GCache.Stats() t.Logf("bufs.GCache.Stats() {%d, %d}", nn, bts) t.Logf("%+v\n", ms) }
func BenchmarkMem(b *testing.B) { f, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) } defer func() { f.Close() os.Remove(f.Name()) }() filer := lldb.NewSimpleFileFiler(f) a, err := lldb.NewAllocator(filer, &lldb.Options{}) if err != nil { b.Error(err) return } a.Compress = true t, _, err := lldb.CreateBTree(a, nil) if err != nil { b.Error(err) return } b.ResetTimer() var key [16]byte for i := uint32(0); int(i) < b.N; i++ { binary.BigEndian.PutUint32(key[:], i) if err = t.Set(key[:], value100); err != nil { b.Error(err) return } } if err := filer.Sync(); err != nil { b.Error(err) return } }
func (db *DB) root() (r *Array, err error) { if r = db._root; r != nil { return } sz, err := db.filer.Size() if err != nil { return } switch { case sz < db.emptySize: panic(fmt.Errorf("internal error: %d", sz)) case sz == db.emptySize: tree, h, err := lldb.CreateBTree(db.alloc, collate) if err != nil { return nil, err } if h != 1 { panic("internal error") } r = &Array{db, tree, nil, "", 0} db._root = r return r, nil default: tree, err := lldb.OpenBTree(db.alloc, collate, 1) if err != nil { return nil, err } r = &Array{db, tree, nil, "", 0} db._root = r return r, nil } }