@@ -130,14 +130,16 @@ class VersionBuilder::Rep {
130130 VersionSet* version_set_;
131131 int num_levels_;
132132 LevelState* levels_;
133- // Store states of levels larger than num_levels_. We do this instead of
133+ // Store sizes of levels larger than num_levels_. We do this instead of
134134 // storing them in levels_ to avoid regression in case there are no files
135135 // on invalid levels. The version is not consistent if in the end the files
136136 // on invalid levels don't cancel out.
137- std::map <int , std::unordered_set< uint64_t >> invalid_levels_ ;
137+ std::unordered_map <int , size_t > invalid_level_sizes_ ;
138138 // Whether there are invalid new files or invalid deletion on levels larger
139139 // than num_levels_.
140140 bool has_invalid_levels_;
141+ // Current levels of table files affected by additions/deletions.
142+ std::unordered_map<uint64_t , int > table_file_levels_;
141143 FileComparator level_zero_cmp_;
142144 FileComparator level_nonzero_cmp_;
143145
@@ -360,65 +362,19 @@ class VersionBuilder::Rep {
360362 return ret_s;
361363 }
362364
363- Status CheckConsistencyForDeletes (VersionEdit* /* edit*/ , uint64_t number,
364- int level) {
365- #ifdef NDEBUG
366- if (!base_vstorage_->force_consistency_checks ()) {
367- // Dont run consistency checks in release mode except if
368- // explicitly asked to
369- return Status::OK ();
370- }
371- #endif
372- // a file to be deleted better exist in the previous version
373- bool found = false ;
374- for (int l = 0 ; !found && l < num_levels_; l++) {
375- const std::vector<FileMetaData*>& base_files =
376- base_vstorage_->LevelFiles (l);
377- for (size_t i = 0 ; i < base_files.size (); i++) {
378- FileMetaData* f = base_files[i];
379- if (f->fd .GetNumber () == number) {
380- found = true ;
381- break ;
382- }
383- }
384- }
385- // if the file did not exist in the previous version, then it
386- // is possibly moved from lower level to higher level in current
387- // version
388- for (int l = level + 1 ; !found && l < num_levels_; l++) {
389- auto & level_added = levels_[l].added_files ;
390- auto got = level_added.find (number);
391- if (got != level_added.end ()) {
392- found = true ;
393- break ;
394- }
395- }
396-
397- // maybe this file was added in a previous edit that was Applied
398- if (!found) {
399- auto & level_added = levels_[level].added_files ;
400- auto got = level_added.find (number);
401- if (got != level_added.end ()) {
402- found = true ;
403- }
404- }
405- if (!found) {
406- fprintf (stderr, " not found %" PRIu64 " \n " , number);
407- return Status::Corruption (" not found " + NumberToString (number));
408- }
409- return Status::OK ();
410- }
411-
412- bool CheckConsistencyForNumLevels () {
365+ bool CheckConsistencyForNumLevels () const {
413366 // Make sure there are no files on or beyond num_levels().
414367 if (has_invalid_levels_) {
415368 return false ;
416369 }
417- for (auto & level : invalid_levels_) {
418- if (level.second .size () > 0 ) {
370+
371+ for (const auto & pair : invalid_level_sizes_) {
372+ const size_t level_size = pair.second ;
373+ if (level_size != 0 ) {
419374 return false ;
420375 }
421376 }
377+
422378 return true ;
423379 }
424380
@@ -479,78 +435,162 @@ class VersionBuilder::Rep {
479435 return Status::OK ();
480436 }
481437
438+ int GetCurrentLevelForTableFile (uint64_t file_number) const {
439+ auto it = table_file_levels_.find (file_number);
440+ if (it != table_file_levels_.end ()) {
441+ return it->second ;
442+ }
443+
444+ assert (base_vstorage_);
445+ return base_vstorage_->GetFileLocation (file_number).GetLevel ();
446+ }
447+
448+ Status ApplyFileDeletion (int level, uint64_t file_number) {
449+ assert (level != VersionStorageInfo::FileLocation::Invalid ().GetLevel ());
450+
451+ const int current_level = GetCurrentLevelForTableFile (file_number);
452+
453+ if (level != current_level) {
454+ if (level >= num_levels_) {
455+ has_invalid_levels_ = true ;
456+ }
457+
458+ std::ostringstream oss;
459+ oss << " Cannot delete table file #" << file_number << " from level "
460+ << level << " since it is " ;
461+ if (current_level ==
462+ VersionStorageInfo::FileLocation::Invalid ().GetLevel ()) {
463+ oss << " not in the LSM tree" ;
464+ } else {
465+ oss << " on level " << current_level;
466+ }
467+
468+ return Status::Corruption (" VersionBuilder" , oss.str ());
469+ }
470+
471+ if (level >= num_levels_) {
472+ assert (invalid_level_sizes_[level] > 0 );
473+ --invalid_level_sizes_[level];
474+
475+ table_file_levels_[file_number] =
476+ VersionStorageInfo::FileLocation::Invalid ().GetLevel ();
477+
478+ return Status::OK ();
479+ }
480+
481+ auto & level_state = levels_[level];
482+
483+ auto & add_files = level_state.added_files ;
484+ auto add_it = add_files.find (file_number);
485+ if (add_it != add_files.end ()) {
486+ UnrefFile (add_it->second );
487+ add_files.erase (add_it);
488+ } else {
489+ auto & del_files = level_state.deleted_files ;
490+ assert (del_files.find (file_number) == del_files.end ());
491+ del_files.emplace (file_number);
492+ }
493+
494+ table_file_levels_[file_number] =
495+ VersionStorageInfo::FileLocation::Invalid ().GetLevel ();
496+
497+ return Status::OK ();
498+ }
499+
500+ Status ApplyFileAddition (int level, const FileMetaData& meta) {
501+ assert (level != VersionStorageInfo::FileLocation::Invalid ().GetLevel ());
502+
503+ const uint64_t file_number = meta.fd .GetNumber ();
504+
505+ const int current_level = GetCurrentLevelForTableFile (file_number);
506+
507+ if (current_level !=
508+ VersionStorageInfo::FileLocation::Invalid ().GetLevel ()) {
509+ if (level >= num_levels_) {
510+ has_invalid_levels_ = true ;
511+ }
512+
513+ std::ostringstream oss;
514+ oss << " Cannot add table file #" << file_number << " to level " << level
515+ << " since it is already in the LSM tree on level " << current_level;
516+ return Status::Corruption (" VersionBuilder" , oss.str ());
517+ }
518+
519+ if (level >= num_levels_) {
520+ ++invalid_level_sizes_[level];
521+ table_file_levels_[file_number] = level;
522+
523+ return Status::OK ();
524+ }
525+
526+ auto & level_state = levels_[level];
527+
528+ auto & del_files = level_state.deleted_files ;
529+ auto del_it = del_files.find (file_number);
530+ if (del_it != del_files.end ()) {
531+ del_files.erase (del_it);
532+ } else {
533+ FileMetaData* const f = new FileMetaData (meta);
534+ f->refs = 1 ;
535+
536+ auto & add_files = level_state.added_files ;
537+ assert (add_files.find (file_number) == add_files.end ());
538+ add_files.emplace (file_number, f);
539+ }
540+
541+ table_file_levels_[file_number] = level;
542+
543+ return Status::OK ();
544+ }
545+
482546 // Apply all of the edits in *edit to the current state.
483547 Status Apply (VersionEdit* edit) {
484- Status s = CheckConsistency (base_vstorage_);
485- if (!s.ok ()) {
486- return s;
548+ {
549+ const Status s = CheckConsistency (base_vstorage_);
550+ if (!s.ok ()) {
551+ return s;
552+ }
487553 }
488554
489555 // Delete files
490- const auto & del = edit->GetDeletedFiles ();
491- for (const auto & del_file : del) {
492- const auto level = del_file.first ;
493- const auto number = del_file.second ;
494- if (level < num_levels_) {
495- levels_[level].deleted_files .insert (number);
496- s = CheckConsistencyForDeletes (edit, number, level);
497- if (!s.ok ()) {
498- return s;
499- }
556+ for (const auto & deleted_file : edit->GetDeletedFiles ()) {
557+ const int level = deleted_file.first ;
558+ const uint64_t file_number = deleted_file.second ;
500559
501- auto exising = levels_[level].added_files .find (number);
502- if (exising != levels_[level].added_files .end ()) {
503- UnrefFile (exising->second );
504- levels_[level].added_files .erase (exising);
505- }
506- } else {
507- if (invalid_levels_[level].erase (number) == 0 ) {
508- // Deleting an non-existing file on invalid level.
509- has_invalid_levels_ = true ;
510- }
560+ const Status s = ApplyFileDeletion (level, file_number);
561+ if (!s.ok ()) {
562+ return s;
511563 }
512564 }
513565
514566 // Add new files
515567 for (const auto & new_file : edit->GetNewFiles ()) {
516568 const int level = new_file.first ;
517- if (level < num_levels_) {
518- FileMetaData* f = new FileMetaData (new_file.second );
519- f->refs = 1 ;
520-
521- assert (levels_[level].added_files .find (f->fd .GetNumber ()) ==
522- levels_[level].added_files .end ());
523- levels_[level].deleted_files .erase (f->fd .GetNumber ());
524- levels_[level].added_files [f->fd .GetNumber ()] = f;
525- } else {
526- uint64_t number = new_file.second .fd .GetNumber ();
527- auto & lvls = invalid_levels_[level];
528- if (lvls.count (number) == 0 ) {
529- lvls.insert (number);
530- } else {
531- // Creating an already existing file on invalid level.
532- has_invalid_levels_ = true ;
533- }
569+ const FileMetaData& meta = new_file.second ;
570+
571+ const Status s = ApplyFileAddition (level, meta);
572+ if (!s.ok ()) {
573+ return s;
534574 }
535575 }
536576
537577 // Add new blob files
538578 for (const auto & blob_file_addition : edit->GetBlobFileAdditions ()) {
539- s = ApplyBlobFileAddition (blob_file_addition);
579+ const Status s = ApplyBlobFileAddition (blob_file_addition);
540580 if (!s.ok ()) {
541581 return s;
542582 }
543583 }
544584
545585 // Increase the amount of garbage for blob files affected by GC
546586 for (const auto & blob_file_garbage : edit->GetBlobFileGarbages ()) {
547- s = ApplyBlobFileGarbage (blob_file_garbage);
587+ const Status s = ApplyBlobFileGarbage (blob_file_garbage);
548588 if (!s.ok ()) {
549589 return s;
550590 }
551591 }
552592
553- return s ;
593+ return Status::OK () ;
554594 }
555595
556596 static std::shared_ptr<BlobFileMetaData> CreateMetaDataForNewBlobFile (
0 commit comments