@@ -7,13 +7,121 @@ package pebble
7
7
import (
8
8
"context"
9
9
"fmt"
10
+ "io"
11
+ "sync"
10
12
13
+ "github.com/cockroachdb/errors"
11
14
"github.com/cockroachdb/pebble/internal/base"
12
15
"github.com/cockroachdb/pebble/internal/keyspan"
13
16
"github.com/cockroachdb/pebble/internal/manifest"
14
17
"github.com/cockroachdb/pebble/internal/treeprinter"
18
+ "github.com/cockroachdb/pebble/sstable/block"
15
19
)
16
20
21
+ // Get gets the value for the given key. It returns ErrNotFound if the DB does
22
+ // not contain the key.
23
+ //
24
+ // The caller should not modify the contents of the returned slice, but it is
25
+ // safe to modify the contents of the argument after Get returns. The returned
26
+ // slice will remain valid until the returned Closer is closed. On success, the
27
+ // caller MUST call closer.Close() or a memory leak will occur.
28
+ func (d * DB ) Get (key []byte ) ([]byte , io.Closer , error ) {
29
+ return d .getInternal (key , nil /* batch */ , nil /* snapshot */ )
30
+ }
31
+
32
+ type getIterAlloc struct {
33
+ dbi Iterator
34
+ keyBuf []byte
35
+ get getIter
36
+ }
37
+
38
+ var getIterAllocPool = sync.Pool {
39
+ New : func () interface {} {
40
+ return & getIterAlloc {}
41
+ },
42
+ }
43
+
44
+ func (d * DB ) getInternal (key []byte , b * Batch , s * Snapshot ) ([]byte , io.Closer , error ) {
45
+ if err := d .closed .Load (); err != nil {
46
+ panic (err )
47
+ }
48
+
49
+ // Grab and reference the current readState. This prevents the underlying
50
+ // files in the associated version from being deleted if there is a current
51
+ // compaction. The readState is unref'd by Iterator.Close().
52
+ readState := d .loadReadState ()
53
+
54
+ // Determine the seqnum to read at after grabbing the read state (current and
55
+ // memtables) above.
56
+ var seqNum base.SeqNum
57
+ if s != nil {
58
+ seqNum = s .seqNum
59
+ } else {
60
+ seqNum = d .mu .versions .visibleSeqNum .Load ()
61
+ }
62
+
63
+ buf := getIterAllocPool .Get ().(* getIterAlloc )
64
+
65
+ get := & buf .get
66
+ * get = getIter {
67
+ comparer : d .opts .Comparer ,
68
+ newIters : d .newIters ,
69
+ snapshot : seqNum ,
70
+ iterOpts : IterOptions {
71
+ // TODO(sumeer): replace with a parameter provided by the caller.
72
+ Category : categoryGet ,
73
+ logger : d .opts .Logger ,
74
+ snapshotForHideObsoletePoints : seqNum ,
75
+ },
76
+ key : key ,
77
+ // Compute the key prefix for bloom filtering.
78
+ prefix : key [:d .opts .Comparer .Split (key )],
79
+ batch : b ,
80
+ mem : readState .memtables ,
81
+ l0 : readState .current .L0SublevelFiles ,
82
+ version : readState .current ,
83
+ }
84
+
85
+ // Strip off memtables which cannot possibly contain the seqNum being read
86
+ // at.
87
+ for len (get .mem ) > 0 {
88
+ n := len (get .mem )
89
+ if logSeqNum := get .mem [n - 1 ].logSeqNum ; logSeqNum < seqNum {
90
+ break
91
+ }
92
+ get .mem = get .mem [:n - 1 ]
93
+ }
94
+
95
+ i := & buf .dbi
96
+ pointIter := get
97
+ * i = Iterator {
98
+ ctx : context .Background (),
99
+ getIterAlloc : buf ,
100
+ iter : pointIter ,
101
+ pointIter : pointIter ,
102
+ merge : d .merge ,
103
+ comparer : * d .opts .Comparer ,
104
+ readState : readState ,
105
+ keyBuf : buf .keyBuf ,
106
+ }
107
+ // Set up a blob value fetcher to use for retrieving values from blob files.
108
+ i .blobValueFetcher .Init (& readState .current .BlobFiles , d .fileCache , block .NoReadEnv )
109
+ get .iiopts .blobValueFetcher = & i .blobValueFetcher
110
+
111
+ if ! i .First () {
112
+ err := i .Close ()
113
+ if err != nil {
114
+ return nil , nil , err
115
+ }
116
+ return nil , nil , ErrNotFound
117
+ }
118
+ val , err := i .ValueAndErr ()
119
+ if err != nil {
120
+ return nil , nil , errors .CombineErrors (err , i .Close ())
121
+ }
122
+ return val , i , nil
123
+ }
124
+
17
125
// getIter is an internal iterator used to perform gets. It iterates through
18
126
// the values for a particular key, level by level. It is not a general purpose
19
127
// internalIterator, but specialized for Get operations so that it loads data
0 commit comments