namespaced.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "encoding/binary"
  9. "time"
  10. "github.com/syndtr/goleveldb/leveldb"
  11. "github.com/syndtr/goleveldb/leveldb/util"
  12. )
  13. // NamespacedKV is a simple key-value store using a specific namespace within
  14. // a leveldb.
  15. type NamespacedKV struct {
  16. db *Lowlevel
  17. prefix []byte
  18. }
  19. // NewNamespacedKV returns a new NamespacedKV that lives in the namespace
  20. // specified by the prefix.
  21. func NewNamespacedKV(db *Lowlevel, prefix string) *NamespacedKV {
  22. prefixBs := []byte(prefix)
  23. // After the conversion from string the cap will be larger than the len (in Go 1.11.5,
  24. // 32 bytes cap for small strings). We need to cut it down to ensure append() calls
  25. // on the prefix make a new allocation.
  26. prefixBs = prefixBs[:len(prefixBs):len(prefixBs)]
  27. return &NamespacedKV{
  28. db: db,
  29. prefix: prefixBs,
  30. }
  31. }
  32. // Reset removes all entries in this namespace.
  33. func (n *NamespacedKV) Reset() {
  34. it := n.db.NewIterator(util.BytesPrefix(n.prefix), nil)
  35. defer it.Release()
  36. batch := new(leveldb.Batch)
  37. for it.Next() {
  38. batch.Delete(it.Key())
  39. if batch.Len() > batchFlushSize {
  40. if err := n.db.Write(batch, nil); err != nil {
  41. panic(err)
  42. }
  43. batch.Reset()
  44. }
  45. }
  46. if batch.Len() > 0 {
  47. if err := n.db.Write(batch, nil); err != nil {
  48. panic(err)
  49. }
  50. }
  51. }
  52. // PutInt64 stores a new int64. Any existing value (even if of another type)
  53. // is overwritten.
  54. func (n *NamespacedKV) PutInt64(key string, val int64) {
  55. var valBs [8]byte
  56. binary.BigEndian.PutUint64(valBs[:], uint64(val))
  57. n.db.Put(n.prefixedKey(key), valBs[:], nil)
  58. }
  59. // Int64 returns the stored value interpreted as an int64 and a boolean that
  60. // is false if no value was stored at the key.
  61. func (n *NamespacedKV) Int64(key string) (int64, bool) {
  62. valBs, err := n.db.Get(n.prefixedKey(key), nil)
  63. if err != nil {
  64. return 0, false
  65. }
  66. val := binary.BigEndian.Uint64(valBs)
  67. return int64(val), true
  68. }
  69. // PutTime stores a new time.Time. Any existing value (even if of another
  70. // type) is overwritten.
  71. func (n *NamespacedKV) PutTime(key string, val time.Time) {
  72. valBs, _ := val.MarshalBinary() // never returns an error
  73. n.db.Put(n.prefixedKey(key), valBs, nil)
  74. }
  75. // Time returns the stored value interpreted as a time.Time and a boolean
  76. // that is false if no value was stored at the key.
  77. func (n NamespacedKV) Time(key string) (time.Time, bool) {
  78. var t time.Time
  79. valBs, err := n.db.Get(n.prefixedKey(key), nil)
  80. if err != nil {
  81. return t, false
  82. }
  83. err = t.UnmarshalBinary(valBs)
  84. return t, err == nil
  85. }
  86. // PutString stores a new string. Any existing value (even if of another type)
  87. // is overwritten.
  88. func (n *NamespacedKV) PutString(key, val string) {
  89. n.db.Put(n.prefixedKey(key), []byte(val), nil)
  90. }
  91. // String returns the stored value interpreted as a string and a boolean that
  92. // is false if no value was stored at the key.
  93. func (n NamespacedKV) String(key string) (string, bool) {
  94. valBs, err := n.db.Get(n.prefixedKey(key), nil)
  95. if err != nil {
  96. return "", false
  97. }
  98. return string(valBs), true
  99. }
  100. // PutBytes stores a new byte slice. Any existing value (even if of another type)
  101. // is overwritten.
  102. func (n *NamespacedKV) PutBytes(key string, val []byte) {
  103. n.db.Put(n.prefixedKey(key), val, nil)
  104. }
  105. // Bytes returns the stored value as a raw byte slice and a boolean that
  106. // is false if no value was stored at the key.
  107. func (n NamespacedKV) Bytes(key string) ([]byte, bool) {
  108. valBs, err := n.db.Get(n.prefixedKey(key), nil)
  109. if err != nil {
  110. return nil, false
  111. }
  112. return valBs, true
  113. }
  114. // PutBool stores a new boolean. Any existing value (even if of another type)
  115. // is overwritten.
  116. func (n *NamespacedKV) PutBool(key string, val bool) {
  117. if val {
  118. n.db.Put(n.prefixedKey(key), []byte{0x0}, nil)
  119. } else {
  120. n.db.Put(n.prefixedKey(key), []byte{0x1}, nil)
  121. }
  122. }
  123. // Bool returns the stored value as a boolean and a boolean that
  124. // is false if no value was stored at the key.
  125. func (n NamespacedKV) Bool(key string) (bool, bool) {
  126. valBs, err := n.db.Get(n.prefixedKey(key), nil)
  127. if err != nil {
  128. return false, false
  129. }
  130. return valBs[0] == 0x0, true
  131. }
  132. // Delete deletes the specified key. It is allowed to delete a nonexistent
  133. // key.
  134. func (n NamespacedKV) Delete(key string) {
  135. n.db.Delete(n.prefixedKey(key), nil)
  136. }
  137. func (n NamespacedKV) prefixedKey(key string) []byte {
  138. return append(n.prefix, []byte(key)...)
  139. }
  140. // Well known namespaces that can be instantiated without knowing the key
  141. // details.
  142. // NewDeviceStatisticsNamespace creates a KV namespace for device statistics
  143. // for the given device.
  144. func NewDeviceStatisticsNamespace(db *Lowlevel, device string) *NamespacedKV {
  145. return NewNamespacedKV(db, string(KeyTypeDeviceStatistic)+device)
  146. }
  147. // NewFolderStatisticsNamespace creates a KV namespace for folder statistics
  148. // for the given folder.
  149. func NewFolderStatisticsNamespace(db *Lowlevel, folder string) *NamespacedKV {
  150. return NewNamespacedKV(db, string(KeyTypeFolderStatistic)+folder)
  151. }
  152. // NewMiscDateNamespace creates a KV namespace for miscellaneous metadata.
  153. func NewMiscDataNamespace(db *Lowlevel) *NamespacedKV {
  154. return NewNamespacedKV(db, string(KeyTypeMiscData))
  155. }