示例#1
0
// 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
}
示例#2
0
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
}
示例#3
0
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
}
示例#4
0
// 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
}
示例#5
0
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
}
示例#6
0
// 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")
	}
}
示例#7
0
// 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
	})
}