// Prev returns the currently enumerated raw KV pair, if it exists and moves to // the previous KV in the key collation order. If there is no KV pair to // return, err == io.EOF is returned. // // This method is safe for concurrent use by multiple goroutines. func (e *Enumerator) Prev() (key, value []interface{}, err error) { if err = e.db.enter(); err != nil { return } defer func() { if e := recover(); e != nil { switch x := e.(type) { case error: err = x default: err = fmt.Errorf("%v", e) } } e.db.leave(&err) }() k, v, err := e.en.Prev() if err != nil { return } if key, err = lldb.DecodeScalars(k); err != nil { return } value, err = lldb.DecodeScalars(v) return }
func (a *Array) get(subscripts ...interface{}) (value interface{}, err error) { key, err := lldb.EncodeScalars(subscripts...) if err != nil { return } val, err := a.bget(key) if err != nil { return } if val == nil { return } va, err := lldb.DecodeScalars(val) if err != nil { return nil, err } value = va if len(va) == 1 { value = va[0] } return }
func collate(a, b []byte) (r int) { da, err := lldb.DecodeScalars(a) if err != nil { panic(err) } db, err := lldb.DecodeScalars(b) if err != nil { panic(err) } r, err = lldb.Collate(da, db, nil) if err != nil { panic(err) } return }
// Slice returns a new Slice from Array, with a subscripts range of [from, to]. // If from is nil it works as 'from lowest existing key'. If to is nil it // works as 'to highest existing key'. func (a *Array) Slice(from, to []interface{}) (s *Slice, err error) { if err = a.db.enter(); err != nil { return } defer func() { if e := recover(); e != nil { err = fmt.Errorf("%v", e) } a.db.leave(&err) }() prefix, err := lldb.DecodeScalars(a.prefix) if err != nil { return } return &Slice{ a: a, prefix: prefix, from: from, to: to, }, nil }
func (a *Array) binc(delta int64, key []byte) (r int64, err error) { _, _, err = a.tree.Put( nil, //TODO buffers append(a.prefix, key...), func(key []byte, old []byte) (new []byte, write bool, err error) { write = true if len(old) != 0 { decoded, err := lldb.DecodeScalars(old) switch { case err != nil: // nop case len(decoded) != 1: // nop default: r, _ = decoded[0].(int64) } } r += delta new, err = lldb.EncodeScalars(r) return }, ) return }
// Do calls f for every subscripts-value pair in s in ascending collation order // of the subscripts. Do returns non nil error for general errors (eg. file // read error). If f returns false or a non nil error then Do terminates and // returns the value of error from f. // // Note: f can get called with a subscripts-value pair which actually may no // longer exist - if some other goroutine introduces such data race. // Coordination required to avoid this situation, if applicable/desirable, must // be provided by the client of dbm. func (s *Slice) Do(f func(subscripts, value []interface{}) (bool, error)) (err error) { var ( db = s.a.db noVal bool ) if err = db.enter(); err != nil { return } doLeave := true defer func() { if doLeave { db.leave(&err) } }() ok, err := s.a.validate(false) if !ok { return err } tree := s.a.tree if !tree.IsMem() && tree.Handle() == 1 { noVal = true } switch { case s.from == nil && s.to == nil: bprefix, err := lldb.EncodeScalars(s.prefix...) if err != nil { return err } enum, _, err := tree.Seek(bprefix) if err != nil { return noEof(err) } for { bk, bv, err := enum.Next() if err != nil { return noEof(err) } k, err := lldb.DecodeScalars(bk) if err != nil { return noEof(err) } if n := len(s.prefix); n != 0 { if len(k) < len(s.prefix) { return nil } c, err := lldb.Collate(k[:n], s.prefix, nil) if err != nil { return err } if c > 0 { return nil } } v, err := lldb.DecodeScalars(bv) if err != nil { return err } doLeave = false if db.leave(&err) != nil { return err } if noVal && v != nil { v = []interface{}{0} } if more, err := f(k[len(s.prefix):], v); !more || err != nil { return noEof(err) } if err = db.enter(); err != nil { return err } doLeave = true } case s.from == nil && s.to != nil: bprefix, err := lldb.EncodeScalars(s.prefix...) if err != nil { return err } enum, _, err := tree.Seek(bprefix) if err != nil { return noEof(err) } to := append(append([]interface{}(nil), s.prefix...), s.to...) for { bk, bv, err := enum.Next() if err != nil { return noEof(err) } k, err := lldb.DecodeScalars(bk) if err != nil { return err } c, err := lldb.Collate(k, to, nil) if err != nil { return err } if c > 0 { return err } v, err := lldb.DecodeScalars(bv) if err != nil { return noEof(err) } doLeave = false if db.leave(&err) != nil { return err } if noVal && v != nil { v = []interface{}{0} } if more, err := f(k[len(s.prefix):], v); !more || err != nil { return noEof(err) } if err = db.enter(); err != nil { return err } doLeave = true } case s.from != nil && s.to == nil: bprefix, err := lldb.EncodeScalars(append(s.prefix, s.from...)...) if err != nil { return err } enum, _, err := tree.Seek(bprefix) if err != nil { return noEof(err) } for { bk, bv, err := enum.Next() if err != nil { return noEof(err) } k, err := lldb.DecodeScalars(bk) if err != nil { return noEof(err) } if n := len(s.prefix); n != 0 { if len(k) < len(s.prefix) { return nil } c, err := lldb.Collate(k[:n], s.prefix, nil) if err != nil { return err } if c > 0 { return nil } } v, err := lldb.DecodeScalars(bv) if err != nil { return err } doLeave = false if db.leave(&err) != nil { return err } if noVal && v != nil { v = []interface{}{0} } if more, err := f(k[len(s.prefix):], v); !more || err != nil { return noEof(err) } if err = db.enter(); err != nil { return err } doLeave = true } case s.from != nil && s.to != nil: bprefix, err := lldb.EncodeScalars(append(s.prefix, s.from...)...) if err != nil { return err } enum, _, err := tree.Seek(bprefix) if err != nil { return noEof(err) } to := append(append([]interface{}(nil), s.prefix...), s.to...) for { bk, bv, err := enum.Next() if err != nil { return noEof(err) } k, err := lldb.DecodeScalars(bk) if err != nil { return noEof(err) } c, err := lldb.Collate(k, to, nil) if err != nil { return err } if c > 0 { return err } v, err := lldb.DecodeScalars(bv) if err != nil { return err } doLeave = false if db.leave(&err) != nil { return err } if noVal && v != nil { v = []interface{}{0} } if more, err := f(k[len(s.prefix):], v); !more || err != nil { return noEof(err) } if err = db.enter(); err != nil { return err } doLeave = true } default: panic("slice.go: internal error") } }
// Clear empties the subtree at subscripts in 'a'. func (a *Array) Clear(subscripts ...interface{}) (err error) { //TODO optimize for clear "everything" if err = a.db.enter(); err != nil { return } doLeave := true defer func() { if e := recover(); e != nil { err = fmt.Errorf("%v", e) } if doLeave { a.db.leave(&err) } }() if t := a.tree; t != nil && !t.IsMem() && a.tree.Handle() == 1 { return &lldb.ErrPERM{Src: "dbm.Array.Clear"} } if ok, err := a.validate(false); !ok { return err } doLeave = false if a.db.leave(&err) != nil { return } a0 := *a a0.prefix = nil prefix, err := lldb.DecodeScalars(a.prefix) if err != nil { panic("internal error") } subscripts = append(prefix, subscripts...) n := len(subscripts) bSubscripts, err := lldb.EncodeScalars(subscripts...) if err != nil { panic("internal error") } s, err := a0.Slice(nil, nil) if err != nil { return } return s.Do(func(actualSubscripts, value []interface{}) (more bool, err error) { if len(actualSubscripts) < n { return } common := actualSubscripts[:n] bcommon, err := lldb.EncodeScalars(common...) if err != nil { panic("internal error") } switch collate(bcommon, bSubscripts) { case -1: return true, nil case 0: return true, a0.Delete(actualSubscripts...) } // case 1: return false, nil }) }