8
8
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
9
10
10
#include " db/db_impl.h"
11
+ #include " rocksdb/env.h"
11
12
#include " rocksdb/db.h"
12
13
#include " util/testharness.h"
14
+ #include " utilities/merge_operators.h"
13
15
14
16
#include < algorithm>
15
17
#include < vector>
@@ -22,10 +24,10 @@ using namespace std;
22
24
class ColumnFamilyTest {
23
25
public:
24
26
ColumnFamilyTest () {
27
+ env_ = Env::Default ();
25
28
dbname_ = test::TmpDir () + " /column_family_test" ;
26
29
db_options_.create_if_missing = true ;
27
- options_.create_if_missing = true ;
28
- DestroyDB (dbname_, options_);
30
+ DestroyDB (dbname_, Options (db_options_, column_family_options_));
29
31
}
30
32
31
33
void Close () {
@@ -37,18 +39,77 @@ class ColumnFamilyTest {
37
39
vector<ColumnFamilyDescriptor> column_families;
38
40
for (auto x : cf) {
39
41
column_families.push_back (
40
- ColumnFamilyDescriptor (x, ColumnFamilyOptions () ));
42
+ ColumnFamilyDescriptor (x, column_family_options_ ));
41
43
}
42
- vector <ColumnFamilyHandle> handles;
43
44
return DB::OpenWithColumnFamilies (db_options_, dbname_, column_families,
44
- &handles , &db_);
45
+ &handles_ , &db_);
45
46
}
46
47
47
- Options options_;
48
+ void Destroy () {
49
+ delete db_;
50
+ db_ = nullptr ;
51
+ ASSERT_OK (DestroyDB (dbname_, Options (db_options_, column_family_options_)));
52
+ }
53
+
54
+ void CreateColumnFamilies (const vector<string>& cfs) {
55
+ int cfi = handles_.size ();
56
+ handles_.resize (cfi + cfs.size ());
57
+ for (auto cf : cfs) {
58
+ ASSERT_OK (db_->CreateColumnFamily (column_family_options_, cf,
59
+ &handles_[cfi++]));
60
+ }
61
+ }
62
+
63
+ Status Put (int cf, const string& key, const string& value) {
64
+ return db_->Put (WriteOptions (), handles_[cf], Slice (key), Slice (value));
65
+ }
66
+ Status Merge (int cf, const string& key, const string& value) {
67
+ return db_->Merge (WriteOptions (), handles_[cf], Slice (key), Slice (value));
68
+ }
69
+
70
+ string Get (int cf, const string& key) {
71
+ ReadOptions options;
72
+ options.verify_checksums = true ;
73
+ string result;
74
+ Status s = db_->Get (options, handles_[cf], Slice (key), &result);
75
+ if (s.IsNotFound ()) {
76
+ result = " NOT_FOUND" ;
77
+ } else if (!s.ok ()) {
78
+ result = s.ToString ();
79
+ }
80
+ return result;
81
+ }
82
+
83
+ void CopyFile (const string& source, const string& destination,
84
+ uint64_t size = 0 ) {
85
+ const EnvOptions soptions;
86
+ unique_ptr<SequentialFile> srcfile;
87
+ ASSERT_OK (env_->NewSequentialFile (source, &srcfile, soptions));
88
+ unique_ptr<WritableFile> destfile;
89
+ ASSERT_OK (env_->NewWritableFile (destination, &destfile, soptions));
90
+
91
+ if (size == 0 ) {
92
+ // default argument means copy everything
93
+ ASSERT_OK (env_->GetFileSize (source, &size));
94
+ }
95
+
96
+ char buffer[4096 ];
97
+ Slice slice;
98
+ while (size > 0 ) {
99
+ uint64_t one = min (uint64_t (sizeof (buffer)), size);
100
+ ASSERT_OK (srcfile->Read (one, &slice, buffer));
101
+ ASSERT_OK (destfile->Append (slice));
102
+ size -= slice.size ();
103
+ }
104
+ ASSERT_OK (destfile->Close ());
105
+ }
106
+
107
+ vector<ColumnFamilyHandle> handles_;
48
108
ColumnFamilyOptions column_family_options_;
49
109
DBOptions db_options_;
50
110
string dbname_;
51
111
DB* db_;
112
+ Env* env_;
52
113
};
53
114
54
115
TEST (ColumnFamilyTest, AddDrop) {
@@ -74,6 +135,108 @@ TEST(ColumnFamilyTest, AddDrop) {
74
135
ASSERT_TRUE (families == vector<string>({" default" , " four" , " one" , " three" }));
75
136
}
76
137
138
+ TEST (ColumnFamilyTest, ReadWrite) {
139
+ ASSERT_OK (Open ({" default" }));
140
+ CreateColumnFamilies ({" one" , " two" });
141
+ Close ();
142
+ ASSERT_OK (Open ({" default" , " one" , " two" }));
143
+ ASSERT_OK (Put (0 , " foo" , " v1" ));
144
+ ASSERT_OK (Put (0 , " bar" , " v2" ));
145
+ ASSERT_OK (Put (1 , " mirko" , " v3" ));
146
+ ASSERT_OK (Put (0 , " foo" , " v2" ));
147
+ ASSERT_OK (Put (2 , " fodor" , " v5" ));
148
+
149
+ for (int iter = 0 ; iter <= 3 ; ++iter) {
150
+ ASSERT_EQ (" v2" , Get (0 , " foo" ));
151
+ ASSERT_EQ (" v2" , Get (0 , " bar" ));
152
+ ASSERT_EQ (" v3" , Get (1 , " mirko" ));
153
+ ASSERT_EQ (" v5" , Get (2 , " fodor" ));
154
+ ASSERT_EQ (" NOT_FOUND" , Get (0 , " fodor" ));
155
+ ASSERT_EQ (" NOT_FOUND" , Get (1 , " fodor" ));
156
+ ASSERT_EQ (" NOT_FOUND" , Get (2 , " foo" ));
157
+ if (iter <= 1 ) {
158
+ // reopen
159
+ Close ();
160
+ ASSERT_OK (Open ({" default" , " one" , " two" }));
161
+ }
162
+ }
163
+ Close ();
164
+ }
165
+
166
+ TEST (ColumnFamilyTest, IgnoreRecoveredLog) {
167
+ string backup_logs = dbname_ + " /backup_logs" ;
168
+
169
+ // delete old files in backup_logs directory
170
+ env_->CreateDirIfMissing (backup_logs);
171
+ vector<string> old_files;
172
+ env_->GetChildren (backup_logs, &old_files);
173
+ for (auto & file : old_files) {
174
+ if (file != " ." && file != " .." ) {
175
+ env_->DeleteFile (backup_logs + " /" + file);
176
+ }
177
+ }
178
+
179
+ column_family_options_.merge_operator =
180
+ MergeOperators::CreateUInt64AddOperator ();
181
+ db_options_.wal_dir = dbname_ + " /logs" ;
182
+ Destroy ();
183
+ ASSERT_OK (Open ({" default" }));
184
+ CreateColumnFamilies ({" cf1" , " cf2" });
185
+
186
+ // fill up the DB
187
+ string one, two, three;
188
+ PutFixed64 (&one, 1 );
189
+ PutFixed64 (&two, 2 );
190
+ PutFixed64 (&three, 3 );
191
+ ASSERT_OK (Merge (0 , " foo" , one));
192
+ ASSERT_OK (Merge (1 , " mirko" , one));
193
+ ASSERT_OK (Merge (0 , " foo" , one));
194
+ ASSERT_OK (Merge (2 , " bla" , one));
195
+ ASSERT_OK (Merge (2 , " fodor" , one));
196
+ ASSERT_OK (Merge (0 , " bar" , one));
197
+ ASSERT_OK (Merge (2 , " bla" , one));
198
+ ASSERT_OK (Merge (1 , " mirko" , two));
199
+ ASSERT_OK (Merge (1 , " franjo" , one));
200
+
201
+ // copy the logs to backup
202
+ vector<string> logs;
203
+ env_->GetChildren (db_options_.wal_dir , &logs);
204
+ for (auto & log : logs) {
205
+ if (log != " .." && log != " ." ) {
206
+ CopyFile (db_options_.wal_dir + " /" + log , backup_logs + " /" + log );
207
+ }
208
+ }
209
+
210
+ // recover the DB
211
+ Close ();
212
+
213
+ // 1. check consistency
214
+ // 2. copy the logs from backup back to WAL dir. if the recovery happens
215
+ // again on the same log files, this should lead to incorrect results
216
+ // due to applying merge operator twice
217
+ // 3. check consistency
218
+ for (int iter = 0 ; iter < 2 ; ++iter) {
219
+ // assert consistency
220
+ ASSERT_OK (Open ({" default" , " cf1" , " cf2" }));
221
+ ASSERT_EQ (two, Get (0 , " foo" ));
222
+ ASSERT_EQ (one, Get (0 , " bar" ));
223
+ ASSERT_EQ (three, Get (1 , " mirko" ));
224
+ ASSERT_EQ (one, Get (1 , " franjo" ));
225
+ ASSERT_EQ (one, Get (2 , " fodor" ));
226
+ ASSERT_EQ (two, Get (2 , " bla" ));
227
+ Close ();
228
+
229
+ if (iter == 0 ) {
230
+ // copy the logs from backup back to wal dir
231
+ for (auto & log : logs) {
232
+ if (log != " .." && log != " ." ) {
233
+ CopyFile (backup_logs + " /" + log , db_options_.wal_dir + " /" + log );
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }
239
+
77
240
} // namespace rocksdb
78
241
79
242
int main (int argc, char ** argv) {
0 commit comments