namespaced.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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/syncthing/syncthing/lib/db/backend"
  11. )
  12. // NamespacedKV is a simple key-value store using a specific namespace within
  13. // a leveldb.
  14. type NamespacedKV struct {
  15. db backend.Backend
  16. prefix string
  17. }
  18. // NewNamespacedKV returns a new NamespacedKV that lives in the namespace
  19. // specified by the prefix.
  20. func NewNamespacedKV(db backend.Backend, prefix string) *NamespacedKV {
  21. return &NamespacedKV{
  22. db: db,
  23. prefix: prefix,
  24. }
  25. }
  26. // PutInt64 stores a new int64. Any existing value (even if of another type)
  27. // is overwritten.
  28. func (n *NamespacedKV) PutInt64(key string, val int64) error {
  29. var valBs [8]byte
  30. binary.BigEndian.PutUint64(valBs[:], uint64(val))
  31. return n.db.Put(n.prefixedKey(key), valBs[:])
  32. }
  33. // Int64 returns the stored value interpreted as an int64 and a boolean that
  34. // is false if no value was stored at the key.
  35. func (n *NamespacedKV) Int64(key string) (int64, bool, error) {
  36. valBs, err := n.db.Get(n.prefixedKey(key))
  37. if err != nil {
  38. return 0, false, filterNotFound(err)
  39. }
  40. val := binary.BigEndian.Uint64(valBs)
  41. return int64(val), true, nil
  42. }
  43. // PutTime stores a new time.Time. Any existing value (even if of another
  44. // type) is overwritten.
  45. func (n *NamespacedKV) PutTime(key string, val time.Time) error {
  46. valBs, _ := val.MarshalBinary() // never returns an error
  47. return n.db.Put(n.prefixedKey(key), valBs)
  48. }
  49. // Time returns the stored value interpreted as a time.Time and a boolean
  50. // that is false if no value was stored at the key.
  51. func (n NamespacedKV) Time(key string) (time.Time, bool, error) {
  52. var t time.Time
  53. valBs, err := n.db.Get(n.prefixedKey(key))
  54. if err != nil {
  55. return t, false, filterNotFound(err)
  56. }
  57. err = t.UnmarshalBinary(valBs)
  58. return t, err == nil, err
  59. }
  60. // PutString stores a new string. Any existing value (even if of another type)
  61. // is overwritten.
  62. func (n *NamespacedKV) PutString(key, val string) error {
  63. return n.db.Put(n.prefixedKey(key), []byte(val))
  64. }
  65. // String returns the stored value interpreted as a string and a boolean that
  66. // is false if no value was stored at the key.
  67. func (n NamespacedKV) String(key string) (string, bool, error) {
  68. valBs, err := n.db.Get(n.prefixedKey(key))
  69. if err != nil {
  70. return "", false, filterNotFound(err)
  71. }
  72. return string(valBs), true, nil
  73. }
  74. // PutBytes stores a new byte slice. Any existing value (even if of another type)
  75. // is overwritten.
  76. func (n *NamespacedKV) PutBytes(key string, val []byte) error {
  77. return n.db.Put(n.prefixedKey(key), val)
  78. }
  79. // Bytes returns the stored value as a raw byte slice and a boolean that
  80. // is false if no value was stored at the key.
  81. func (n NamespacedKV) Bytes(key string) ([]byte, bool, error) {
  82. valBs, err := n.db.Get(n.prefixedKey(key))
  83. if err != nil {
  84. return nil, false, filterNotFound(err)
  85. }
  86. return valBs, true, nil
  87. }
  88. // PutBool stores a new boolean. Any existing value (even if of another type)
  89. // is overwritten.
  90. func (n *NamespacedKV) PutBool(key string, val bool) error {
  91. if val {
  92. return n.db.Put(n.prefixedKey(key), []byte{0x0})
  93. }
  94. return n.db.Put(n.prefixedKey(key), []byte{0x1})
  95. }
  96. // Bool returns the stored value as a boolean and a boolean that
  97. // is false if no value was stored at the key.
  98. func (n NamespacedKV) Bool(key string) (bool, bool, error) {
  99. valBs, err := n.db.Get(n.prefixedKey(key))
  100. if err != nil {
  101. return false, false, filterNotFound(err)
  102. }
  103. return valBs[0] == 0x0, true, nil
  104. }
  105. // Delete deletes the specified key. It is allowed to delete a nonexistent
  106. // key.
  107. func (n NamespacedKV) Delete(key string) error {
  108. return n.db.Delete(n.prefixedKey(key))
  109. }
  110. func (n NamespacedKV) prefixedKey(key string) []byte {
  111. return []byte(n.prefix + key)
  112. }
  113. // Well known namespaces that can be instantiated without knowing the key
  114. // details.
  115. // NewDeviceStatisticsNamespace creates a KV namespace for device statistics
  116. // for the given device.
  117. func NewDeviceStatisticsNamespace(db backend.Backend, device string) *NamespacedKV {
  118. return NewNamespacedKV(db, string(KeyTypeDeviceStatistic)+device)
  119. }
  120. // NewFolderStatisticsNamespace creates a KV namespace for folder statistics
  121. // for the given folder.
  122. func NewFolderStatisticsNamespace(db backend.Backend, folder string) *NamespacedKV {
  123. return NewNamespacedKV(db, string(KeyTypeFolderStatistic)+folder)
  124. }
  125. // NewMiscDataNamespace creates a KV namespace for miscellaneous metadata.
  126. func NewMiscDataNamespace(db backend.Backend) *NamespacedKV {
  127. return NewNamespacedKV(db, string(KeyTypeMiscData))
  128. }
  129. func filterNotFound(err error) error {
  130. if backend.IsNotFound(err) {
  131. return nil
  132. }
  133. return err
  134. }