transactions.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 olddb
  7. import (
  8. "fmt"
  9. "google.golang.org/protobuf/proto"
  10. "github.com/syncthing/syncthing/internal/db/olddb/backend"
  11. "github.com/syncthing/syncthing/internal/gen/bep"
  12. "github.com/syncthing/syncthing/internal/gen/dbproto"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. )
  15. // A readOnlyTransaction represents a database snapshot.
  16. type readOnlyTransaction struct {
  17. backend.ReadTransaction
  18. keyer keyer
  19. }
  20. func (db *deprecatedLowlevel) newReadOnlyTransaction() (readOnlyTransaction, error) {
  21. tran, err := db.NewReadTransaction()
  22. if err != nil {
  23. return readOnlyTransaction{}, err
  24. }
  25. return db.readOnlyTransactionFromBackendTransaction(tran), nil
  26. }
  27. func (db *deprecatedLowlevel) readOnlyTransactionFromBackendTransaction(tran backend.ReadTransaction) readOnlyTransaction {
  28. return readOnlyTransaction{
  29. ReadTransaction: tran,
  30. keyer: db.keyer,
  31. }
  32. }
  33. func (t readOnlyTransaction) close() {
  34. t.Release()
  35. }
  36. func (t readOnlyTransaction) getFileByKey(key []byte) (protocol.FileInfo, bool, error) {
  37. f, ok, err := t.getFileTrunc(key, false)
  38. if err != nil || !ok {
  39. return protocol.FileInfo{}, false, err
  40. }
  41. return f, true, nil
  42. }
  43. func (t readOnlyTransaction) getFileTrunc(key []byte, trunc bool) (protocol.FileInfo, bool, error) {
  44. bs, err := t.Get(key)
  45. if backend.IsNotFound(err) {
  46. return protocol.FileInfo{}, false, nil
  47. }
  48. if err != nil {
  49. return protocol.FileInfo{}, false, err
  50. }
  51. f, err := t.unmarshalTrunc(bs, trunc)
  52. if backend.IsNotFound(err) {
  53. return protocol.FileInfo{}, false, nil
  54. }
  55. if err != nil {
  56. return protocol.FileInfo{}, false, err
  57. }
  58. return f, true, nil
  59. }
  60. func (t readOnlyTransaction) unmarshalTrunc(bs []byte, trunc bool) (protocol.FileInfo, error) {
  61. if trunc {
  62. var bfi dbproto.FileInfoTruncated
  63. err := proto.Unmarshal(bs, &bfi)
  64. if err != nil {
  65. return protocol.FileInfo{}, err
  66. }
  67. if err := t.fillTruncated(&bfi); err != nil {
  68. return protocol.FileInfo{}, err
  69. }
  70. return protocol.FileInfoFromDBTruncated(&bfi), nil
  71. }
  72. var bfi bep.FileInfo
  73. err := proto.Unmarshal(bs, &bfi)
  74. if err != nil {
  75. return protocol.FileInfo{}, err
  76. }
  77. if err := t.fillFileInfo(&bfi); err != nil {
  78. return protocol.FileInfo{}, err
  79. }
  80. return protocol.FileInfoFromDB(&bfi), nil
  81. }
  82. type blocksIndirectionError struct {
  83. err error
  84. }
  85. func (e *blocksIndirectionError) Error() string {
  86. return fmt.Sprintf("filling Blocks: %v", e.err)
  87. }
  88. func (e *blocksIndirectionError) Unwrap() error {
  89. return e.err
  90. }
  91. // fillFileInfo follows the (possible) indirection of blocks and version
  92. // vector and fills it out.
  93. func (t readOnlyTransaction) fillFileInfo(fi *bep.FileInfo) error {
  94. var key []byte
  95. if len(fi.Blocks) == 0 && len(fi.BlocksHash) != 0 {
  96. // The blocks list is indirected and we need to load it.
  97. key = t.keyer.GenerateBlockListKey(key, fi.BlocksHash)
  98. bs, err := t.Get(key)
  99. if err != nil {
  100. return &blocksIndirectionError{err}
  101. }
  102. var bl dbproto.BlockList
  103. if err := proto.Unmarshal(bs, &bl); err != nil {
  104. return err
  105. }
  106. fi.Blocks = bl.Blocks
  107. }
  108. if len(fi.VersionHash) != 0 {
  109. key = t.keyer.GenerateVersionKey(key, fi.VersionHash)
  110. bs, err := t.Get(key)
  111. if err != nil {
  112. return fmt.Errorf("filling Version: %w", err)
  113. }
  114. var v bep.Vector
  115. if err := proto.Unmarshal(bs, &v); err != nil {
  116. return err
  117. }
  118. fi.Version = &v
  119. }
  120. return nil
  121. }
  122. // fillTruncated follows the (possible) indirection of version vector and
  123. // fills it.
  124. func (t readOnlyTransaction) fillTruncated(fi *dbproto.FileInfoTruncated) error {
  125. var key []byte
  126. if len(fi.VersionHash) == 0 {
  127. return nil
  128. }
  129. key = t.keyer.GenerateVersionKey(key, fi.VersionHash)
  130. bs, err := t.Get(key)
  131. if err != nil {
  132. return err
  133. }
  134. var v bep.Vector
  135. if err := proto.Unmarshal(bs, &v); err != nil {
  136. return err
  137. }
  138. fi.Version = &v
  139. return nil
  140. }
  141. func (t *readOnlyTransaction) withHaveSequence(folder []byte, startSeq int64, fn Iterator) error {
  142. first, err := t.keyer.GenerateSequenceKey(nil, folder, startSeq)
  143. if err != nil {
  144. return err
  145. }
  146. last, err := t.keyer.GenerateSequenceKey(nil, folder, maxInt64)
  147. if err != nil {
  148. return err
  149. }
  150. dbi, err := t.NewRangeIterator(first, last)
  151. if err != nil {
  152. return err
  153. }
  154. defer dbi.Release()
  155. for dbi.Next() {
  156. f, ok, err := t.getFileByKey(dbi.Value())
  157. if err != nil {
  158. return err
  159. }
  160. if !ok {
  161. continue
  162. }
  163. if !fn(f) {
  164. return nil
  165. }
  166. }
  167. return dbi.Error()
  168. }