func encVal(val interface{}) (r []byte, err error) { switch x := val.(type) { case []interface{}: return lldb.EncodeScalars(x...) default: return lldb.EncodeScalars(x) } }
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 (a *Array) delete(subscripts ...interface{}) (err error) { key, err := lldb.EncodeScalars(subscripts...) if err != nil { return } return a.bdelete(key) }
func (a *Array) inc(delta int64, subscripts ...interface{}) (val int64, err error) { key, err := lldb.EncodeScalars(subscripts...) if err != nil { return } return a.binc(delta, key) }
func (a *Array) array(subscripts ...interface{}) (r Array, err error) { r = *a prefix, err := lldb.EncodeScalars(subscripts...) if err != nil { return } r.prefix = append(bpack(r.prefix), prefix...) return }
func (a *Array) set(value interface{}, subscripts ...interface{}) (err error) { val, err := encVal(value) if err != nil { return } key, err := lldb.EncodeScalars(subscripts...) if err != nil { return } return a.bset(val, key) }
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 }) }