@@ -28,8 +28,12 @@ class SpecialEnv : public EnvWrapper {
28
28
// sstable Sync() calls are blocked while this pointer is non-NULL.
29
29
port::AtomicPointer delay_sstable_sync_;
30
30
31
+ // Simulate no-space errors while this pointer is non-NULL.
32
+ port::AtomicPointer no_space_;
33
+
31
34
explicit SpecialEnv (Env* base) : EnvWrapper(base) {
32
35
delay_sstable_sync_.Release_Store (NULL );
36
+ no_space_.Release_Store (NULL );
33
37
}
34
38
35
39
Status NewWritableFile (const std::string& f, WritableFile** r) {
@@ -44,7 +48,14 @@ class SpecialEnv : public EnvWrapper {
44
48
base_ (base) {
45
49
}
46
50
~SSTableFile () { delete base_; }
47
- Status Append (const Slice& data) { return base_->Append (data); }
51
+ Status Append (const Slice& data) {
52
+ if (env_->no_space_ .Acquire_Load () != NULL ) {
53
+ // Drop writes on the floor
54
+ return Status::OK ();
55
+ } else {
56
+ return base_->Append (data);
57
+ }
58
+ }
48
59
Status Close () { return base_->Close (); }
49
60
Status Flush () { return base_->Flush (); }
50
61
Status Sync () {
@@ -239,6 +250,12 @@ class DBTest {
239
250
return result;
240
251
}
241
252
253
+ int CountFiles () {
254
+ std::vector<std::string> files;
255
+ env_->GetChildren (dbname_, &files);
256
+ return static_cast <int >(files.size ());
257
+ }
258
+
242
259
uint64_t Size (const Slice& start, const Slice& limit) {
243
260
Range r (start, limit);
244
261
uint64_t size;
@@ -1266,6 +1283,37 @@ TEST(DBTest, DBOpen_Options) {
1266
1283
db = NULL ;
1267
1284
}
1268
1285
1286
+ // Check that number of files does not grow when we are out of space
1287
+ TEST (DBTest, NoSpace) {
1288
+ Options options;
1289
+ options.env = env_;
1290
+ Reopen (&options);
1291
+
1292
+ ASSERT_OK (Put (" foo" , " v1" ));
1293
+ ASSERT_EQ (" v1" , Get (" foo" ));
1294
+ Compact (" a" , " z" );
1295
+ const int num_files = CountFiles ();
1296
+ env_->no_space_ .Release_Store (env_); // Force out-of-space errors
1297
+ for (int i = 0 ; i < 10 ; i++) {
1298
+ for (int level = 0 ; level < config::kNumLevels -1 ; level++) {
1299
+ dbfull ()->TEST_CompactRange (level, NULL , NULL );
1300
+ }
1301
+ }
1302
+ env_->no_space_ .Release_Store (NULL );
1303
+ ASSERT_LT (CountFiles (), num_files + 5 );
1304
+ }
1305
+
1306
+ TEST (DBTest, FilesDeletedAfterCompaction) {
1307
+ ASSERT_OK (Put (" foo" , " v2" ));
1308
+ Compact (" a" , " z" );
1309
+ const int num_files = CountFiles ();
1310
+ for (int i = 0 ; i < 10 ; i++) {
1311
+ ASSERT_OK (Put (" foo" , " v2" ));
1312
+ Compact (" a" , " z" );
1313
+ }
1314
+ ASSERT_EQ (CountFiles (), num_files);
1315
+ }
1316
+
1269
1317
// Multi-threaded test:
1270
1318
namespace {
1271
1319
@@ -1287,14 +1335,15 @@ struct MTThread {
1287
1335
1288
1336
static void MTThreadBody (void * arg) {
1289
1337
MTThread* t = reinterpret_cast <MTThread*>(arg);
1338
+ int id = t->id ;
1290
1339
DB* db = t->state ->test ->db_ ;
1291
1340
uintptr_t counter = 0 ;
1292
- fprintf (stderr, " ... starting thread %d\n " , t-> id );
1293
- Random rnd (1000 + t-> id );
1341
+ fprintf (stderr, " ... starting thread %d\n " , id);
1342
+ Random rnd (1000 + id);
1294
1343
std::string value;
1295
1344
char valbuf[1500 ];
1296
1345
while (t->state ->stop .Acquire_Load () == NULL ) {
1297
- t->state ->counter [t-> id ].Release_Store (reinterpret_cast <void *>(counter));
1346
+ t->state ->counter [id].Release_Store (reinterpret_cast <void *>(counter));
1298
1347
1299
1348
int key = rnd.Uniform (kNumKeys );
1300
1349
char keybuf[20 ];
@@ -1304,7 +1353,7 @@ static void MTThreadBody(void* arg) {
1304
1353
// Write values of the form <key, my id, counter>.
1305
1354
// We add some padding for force compactions.
1306
1355
snprintf (valbuf, sizeof (valbuf), " %d.%d.%-1000d" ,
1307
- key, t-> id , static_cast <int >(counter));
1356
+ key, id, static_cast <int >(counter));
1308
1357
ASSERT_OK (db->Put (WriteOptions (), Slice (keybuf), Slice (valbuf)));
1309
1358
} else {
1310
1359
// Read a value and verify that it matches the pattern written above.
@@ -1325,8 +1374,8 @@ static void MTThreadBody(void* arg) {
1325
1374
}
1326
1375
counter++;
1327
1376
}
1328
- t->state ->thread_done [t-> id ].Release_Store (t);
1329
- fprintf (stderr, " ... stopping thread %d after %d ops\n " , t-> id , int (counter));
1377
+ t->state ->thread_done [id].Release_Store (t);
1378
+ fprintf (stderr, " ... stopping thread %d after %d ops\n " , id, int (counter));
1330
1379
}
1331
1380
1332
1381
} // namespace
0 commit comments