f9b2f0ad79
Summary: This diff fixes two bugs: * Increase sequence number even if WriteBatch fails. This is important because WriteBatches in WAL logs have implictly increasing sequence number, even if one update in a write batch fails. This caused some writes to get lost in my CF stress testing * Tolerate 'invalid column family' errors on recovery. When a column family is dropped, processing WAL logs can have some WriteBatches that still refer to the dropped column family. In recovery environment, we want to ignore those errors. In client's Write() code path, however, we want to return the failure to the client if he's trying to add data to invalid column family. Test Plan: db_stress's verification works now Reviewers: dhruba, haobo CC: leveldb Differential Revision: https://reviews.facebook.net/D16533
111 lines
3.7 KiB
C++
111 lines
3.7 KiB
C++
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
//
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
|
|
#pragma once
|
|
#include "rocksdb/types.h"
|
|
#include "rocksdb/write_batch.h"
|
|
#include "rocksdb/db.h"
|
|
#include "rocksdb/options.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
class MemTable;
|
|
|
|
class ColumnFamilyMemTables {
|
|
public:
|
|
virtual ~ColumnFamilyMemTables() {}
|
|
virtual bool Seek(uint32_t column_family_id) = 0;
|
|
// returns true if the update to memtable should be ignored
|
|
// (useful when recovering from log whose updates have already
|
|
// been processed)
|
|
virtual uint64_t GetLogNumber() const = 0;
|
|
virtual MemTable* GetMemTable() const = 0;
|
|
virtual const Options* GetFullOptions() const = 0;
|
|
virtual ColumnFamilyHandle* GetColumnFamilyHandle() = 0;
|
|
};
|
|
|
|
class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
|
|
public:
|
|
ColumnFamilyMemTablesDefault(MemTable* mem, const Options* options)
|
|
: ok_(false), mem_(mem), options_(options) {}
|
|
|
|
bool Seek(uint32_t column_family_id) override {
|
|
ok_ = (column_family_id == 0);
|
|
return ok_;
|
|
}
|
|
|
|
uint64_t GetLogNumber() const override { return 0; }
|
|
|
|
MemTable* GetMemTable() const override {
|
|
assert(ok_);
|
|
return mem_;
|
|
}
|
|
|
|
const Options* GetFullOptions() const override {
|
|
assert(ok_);
|
|
return options_;
|
|
}
|
|
|
|
ColumnFamilyHandle* GetColumnFamilyHandle() override { return nullptr; }
|
|
|
|
private:
|
|
bool ok_;
|
|
MemTable* mem_;
|
|
const Options* const options_;
|
|
};
|
|
|
|
// WriteBatchInternal provides static methods for manipulating a
|
|
// WriteBatch that we don't want in the public WriteBatch interface.
|
|
class WriteBatchInternal {
|
|
public:
|
|
// Return the number of entries in the batch.
|
|
static int Count(const WriteBatch* batch);
|
|
|
|
// Set the count for the number of entries in the batch.
|
|
static void SetCount(WriteBatch* batch, int n);
|
|
|
|
// Return the seqeunce number for the start of this batch.
|
|
static SequenceNumber Sequence(const WriteBatch* batch);
|
|
|
|
// Store the specified number as the seqeunce number for the start of
|
|
// this batch.
|
|
static void SetSequence(WriteBatch* batch, SequenceNumber seq);
|
|
|
|
static Slice Contents(const WriteBatch* batch) {
|
|
return Slice(batch->rep_);
|
|
}
|
|
|
|
static size_t ByteSize(const WriteBatch* batch) {
|
|
return batch->rep_.size();
|
|
}
|
|
|
|
static void SetContents(WriteBatch* batch, const Slice& contents);
|
|
|
|
// Inserts batch entries into memtable
|
|
// If dont_filter_deletes is false AND options.filter_deletes is true,
|
|
// then --> Drops deletes in batch if db->KeyMayExist returns false
|
|
// If recovery == true, this means InsertInto is executed on a recovery
|
|
// code-path. WriteBatch referencing a dropped column family can be
|
|
// found on a recovery code-path and should be ignored (recovery should not
|
|
// fail). Additionally, the memtable will be updated only if
|
|
// memtables->GetLogNumber() >= log_number
|
|
// However, if recovery == false, any WriteBatch referencing
|
|
// non-existing column family will return a failure. Also, log_number is
|
|
// ignored in that case
|
|
static Status InsertInto(const WriteBatch* batch,
|
|
ColumnFamilyMemTables* memtables,
|
|
bool recovery = false, uint64_t log_number = 0,
|
|
DB* db = nullptr,
|
|
const bool dont_filter_deletes = true);
|
|
|
|
static void Append(WriteBatch* dst, const WriteBatch* src);
|
|
};
|
|
|
|
} // namespace rocksdb
|