func (o *Options) acidFiler(db *DB, f lldb.Filer) (r lldb.Filer, err error) { switch o._ACID { default: panic("internal error") case _ACIDTransactions: if r, err = lldb.NewRollbackFiler( f, func(sz int64) error { return f.Truncate(sz) }, f, ); err != nil { return nil, err } return r, nil case _ACIDFull: if r, err = lldb.NewACIDFiler(f, o.wal); err != nil { return nil, err } db.acidState = stIdle db.gracePeriod = o._GracePeriod if o._GracePeriod == 0 { panic("internal error") } return r, nil } }
func (o *Options) acidFiler(db *DB, f lldb.Filer) (r lldb.Filer, err error) { switch o.ACID { default: panic("internal error") case ACIDNone: r = f case ACIDTransactions: var rf *lldb.RollbackFiler if rf, err = lldb.NewRollbackFiler( f, func(sz int64) error { return f.Truncate(sz) }, f, ); err != nil { return } db.xact = true r = rf case ACIDFull: if r, err = lldb.NewACIDFiler(f, o.wal); err != nil { return } db.acidState = stIdle db.gracePeriod = o.GracePeriod db.xact = true if o.GracePeriod == 0 { db.acidState = stDisabled break } // Ensure GOMAXPROCS > 1, required for ACID FSM if n := runtime.GOMAXPROCS(0); n > 1 { return } runtime.GOMAXPROCS(2) } return }
func create(f *os.File, filer lldb.Filer, opts *Options, isMem bool) (db *DB, err error) { defer func() { lock := opts.lock if err != nil && lock != nil { n := lock.Name() lock.Close() os.Remove(n) 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: "dbm.Create.WriteAt", Path: filer.Name(), Err: err} } db = &DB{emptySize: 128, f: f, lock: opts.lock, closed: make(chan bool)} 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: "dbm.Create", Path: filer.Name(), Err: err} } db.alloc.Compress = compress db.isMem = isMem return db, db.boot() }
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 }
// OpenFromFiler is like Open but it accepts an arbitrary backing storage // provided by filer. func OpenFromFiler(filer lldb.Filer, opts *Options) (db *DB, err error) { opts = opts.clone() opts._ACID = _ACIDFull defer func() { if db != nil { db.opts = opts } }() defer func() { lock := opts.lock if err != nil && lock != nil { lock.Close() db = nil } if err != nil { if db != nil { db.Close() db = nil } } }() name := filer.Name() if err = opts.check(name, false, true); err != nil { return } sz, err := filer.Size() if err != nil { return } if sz%16 != 0 { return nil, &os.PathError{Op: "kv.Open:", Path: name, Err: fmt.Errorf("file size %d(%#x) is not 0 (mod 16)", sz, sz)} } var b [16]byte if n, err := filer.ReadAt(b[:], 0); n != 16 || err != nil { return nil, &os.PathError{Op: "kv.Open.ReadAt", Path: name, Err: err} } var h header if err = h.rd(b[:]); err != nil { return nil, &os.PathError{Op: "kv.Open:validate header", Path: name, Err: err} } db = &DB{lock: opts.lock} if filer, err = opts.acidFiler(db, filer); err != nil { return nil, err } db.filer = filer switch h.ver { default: return nil, &os.PathError{Op: "kv.Open", Path: name, Err: fmt.Errorf("unknown/unsupported kv file format version %#x", h.ver)} case 0x00: if _, err = open00(name, db); err != nil { return nil, err } } db.root, err = lldb.OpenBTree(db.alloc, opts.Compare, 1) db.wal = opts.wal if opts.VerifyDbAfterOpen { err = verifyAllocator(db.alloc) } return }