| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // Copyright (C) 2014 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- package db
- import (
- "encoding/binary"
- "time"
- "github.com/syndtr/goleveldb/leveldb/util"
- )
- // NamespacedKV is a simple key-value store using a specific namespace within
- // a leveldb.
- type NamespacedKV struct {
- db *Lowlevel
- prefix []byte
- }
- // NewNamespacedKV returns a new NamespacedKV that lives in the namespace
- // specified by the prefix.
- func NewNamespacedKV(db *Lowlevel, prefix string) *NamespacedKV {
- prefixBs := []byte(prefix)
- // After the conversion from string the cap will be larger than the len (in Go 1.11.5,
- // 32 bytes cap for small strings). We need to cut it down to ensure append() calls
- // on the prefix make a new allocation.
- prefixBs = prefixBs[:len(prefixBs):len(prefixBs)]
- return &NamespacedKV{
- db: db,
- prefix: prefixBs,
- }
- }
- // Reset removes all entries in this namespace.
- func (n *NamespacedKV) Reset() {
- it := n.db.NewIterator(util.BytesPrefix(n.prefix), nil)
- defer it.Release()
- batch := n.db.newBatch()
- for it.Next() {
- batch.Delete(it.Key())
- batch.checkFlush()
- }
- batch.flush()
- }
- // PutInt64 stores a new int64. Any existing value (even if of another type)
- // is overwritten.
- func (n *NamespacedKV) PutInt64(key string, val int64) {
- var valBs [8]byte
- binary.BigEndian.PutUint64(valBs[:], uint64(val))
- n.db.Put(n.prefixedKey(key), valBs[:], nil)
- }
- // Int64 returns the stored value interpreted as an int64 and a boolean that
- // is false if no value was stored at the key.
- func (n *NamespacedKV) Int64(key string) (int64, bool) {
- valBs, err := n.db.Get(n.prefixedKey(key), nil)
- if err != nil {
- return 0, false
- }
- val := binary.BigEndian.Uint64(valBs)
- return int64(val), true
- }
- // PutTime stores a new time.Time. Any existing value (even if of another
- // type) is overwritten.
- func (n *NamespacedKV) PutTime(key string, val time.Time) {
- valBs, _ := val.MarshalBinary() // never returns an error
- n.db.Put(n.prefixedKey(key), valBs, nil)
- }
- // Time returns the stored value interpreted as a time.Time and a boolean
- // that is false if no value was stored at the key.
- func (n NamespacedKV) Time(key string) (time.Time, bool) {
- var t time.Time
- valBs, err := n.db.Get(n.prefixedKey(key), nil)
- if err != nil {
- return t, false
- }
- err = t.UnmarshalBinary(valBs)
- return t, err == nil
- }
- // PutString stores a new string. Any existing value (even if of another type)
- // is overwritten.
- func (n *NamespacedKV) PutString(key, val string) {
- n.db.Put(n.prefixedKey(key), []byte(val), nil)
- }
- // String returns the stored value interpreted as a string and a boolean that
- // is false if no value was stored at the key.
- func (n NamespacedKV) String(key string) (string, bool) {
- valBs, err := n.db.Get(n.prefixedKey(key), nil)
- if err != nil {
- return "", false
- }
- return string(valBs), true
- }
- // PutBytes stores a new byte slice. Any existing value (even if of another type)
- // is overwritten.
- func (n *NamespacedKV) PutBytes(key string, val []byte) {
- n.db.Put(n.prefixedKey(key), val, nil)
- }
- // Bytes returns the stored value as a raw byte slice and a boolean that
- // is false if no value was stored at the key.
- func (n NamespacedKV) Bytes(key string) ([]byte, bool) {
- valBs, err := n.db.Get(n.prefixedKey(key), nil)
- if err != nil {
- return nil, false
- }
- return valBs, true
- }
- // PutBool stores a new boolean. Any existing value (even if of another type)
- // is overwritten.
- func (n *NamespacedKV) PutBool(key string, val bool) {
- if val {
- n.db.Put(n.prefixedKey(key), []byte{0x0}, nil)
- } else {
- n.db.Put(n.prefixedKey(key), []byte{0x1}, nil)
- }
- }
- // Bool returns the stored value as a boolean and a boolean that
- // is false if no value was stored at the key.
- func (n NamespacedKV) Bool(key string) (bool, bool) {
- valBs, err := n.db.Get(n.prefixedKey(key), nil)
- if err != nil {
- return false, false
- }
- return valBs[0] == 0x0, true
- }
- // Delete deletes the specified key. It is allowed to delete a nonexistent
- // key.
- func (n NamespacedKV) Delete(key string) {
- n.db.Delete(n.prefixedKey(key), nil)
- }
- func (n NamespacedKV) prefixedKey(key string) []byte {
- return append(n.prefix, []byte(key)...)
- }
- // Well known namespaces that can be instantiated without knowing the key
- // details.
- // NewDeviceStatisticsNamespace creates a KV namespace for device statistics
- // for the given device.
- func NewDeviceStatisticsNamespace(db *Lowlevel, device string) *NamespacedKV {
- return NewNamespacedKV(db, string(KeyTypeDeviceStatistic)+device)
- }
- // NewFolderStatisticsNamespace creates a KV namespace for folder statistics
- // for the given folder.
- func NewFolderStatisticsNamespace(db *Lowlevel, folder string) *NamespacedKV {
- return NewNamespacedKV(db, string(KeyTypeFolderStatistic)+folder)
- }
- // NewMiscDateNamespace creates a KV namespace for miscellaneous metadata.
- func NewMiscDataNamespace(db *Lowlevel) *NamespacedKV {
- return NewNamespacedKV(db, string(KeyTypeMiscData))
- }
|