// record_store.h
/**
* Copyright (C) 2013 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/base/owned_pointer_vector.h"
#include "mongo/bson/mutable/damage_vector.h"
#include "mongo/db/diskloc.h"
#include "mongo/db/exec/collection_scan_common.h"
#include "mongo/db/storage/record_data.h"
namespace mongo {
class CappedDocumentDeleteCallback;
class Collection;
struct CompactOptions;
struct CompactStats;
class DocWriter;
class MAdvise;
class NamespaceDetails;
class OperationContext;
class Record;
class RecordStoreCompactAdaptor;
class RecordStore;
struct ValidateResults;
class ValidateAdaptor;
/**
* Allows inserting a Record "in-place" without creating a copy ahead of time.
*/
class DocWriter {
public:
virtual ~DocWriter() {}
virtual void writeDocument( char* buf ) const = 0;
virtual size_t documentSize() const = 0;
virtual bool addPadding() const { return true; }
};
/**
* @see RecordStore::updateRecord
*/
class UpdateMoveNotifier {
public:
virtual ~UpdateMoveNotifier(){}
virtual Status recordStoreGoingToMove( OperationContext* txn,
const DiskLoc& oldLocation,
const char* oldBuffer,
size_t oldSize ) = 0;
};
/**
* A RecordIterator provides an interface for walking over a RecordStore.
* The details of navigating the collection's structure are below this interface.
*/
class RecordIterator {
public:
virtual ~RecordIterator() { }
// True if getNext will produce no more data, false otherwise.
virtual bool isEOF() = 0;
// Return the DiskLoc that the iterator points at. Returns DiskLoc() if isEOF.
virtual DiskLoc curr() = 0;
// Return the DiskLoc that the iterator points at and move the iterator to the next item
// from the collection. Returns DiskLoc() if isEOF.
virtual DiskLoc getNext() = 0;
// Can only be called after saveState and before restoreState.
virtual void invalidate(const DiskLoc& dl) = 0;
// Save any state required to resume operation (without crashing) after DiskLoc deletion or
// a collection drop.
virtual void saveState() = 0;
// Returns true if collection still exists, false otherwise.
// The state of the iterator may be restored into a different context
// than the one it was created in.
virtual bool restoreState(OperationContext* txn) = 0;
// normally this will just go back to the RecordStore and convert
// but this gives the iterator an oppurtnity to optimize
virtual RecordData dataFor( const DiskLoc& loc ) const = 0;
};
class RecordStore {
MONGO_DISALLOW_COPYING(RecordStore);
public:
RecordStore( const StringData& ns ) : _ns(ns.toString()) { }
virtual ~RecordStore() { }
// META
// name of the RecordStore implementation
virtual const char* name() const = 0;
virtual const std::string& ns() const { return _ns; }
virtual long long dataSize( OperationContext* txn ) const = 0;
virtual long long numRecords( OperationContext* txn ) const = 0;
virtual bool isCapped() const = 0;
virtual void setCappedDeleteCallback(CappedDocumentDeleteCallback*) {invariant( false );}
/**
* @param extraInfo - optional more debug info
* @param level - optional, level of debug info to put in (higher is more)
*/
virtual int64_t storageSize( OperationContext* txn,
BSONObjBuilder* extraInfo = NULL,
int infoLevel = 0 ) const = 0;
// CRUD related
virtual RecordData dataFor( OperationContext* txn, const DiskLoc& loc) const = 0;
/**
* @param out - If the record exists, the contents of this are set.
* @return true iff there is a Record for loc
*/
virtual bool findRecord( OperationContext* txn,
const DiskLoc& loc,
RecordData* out ) const = 0;
virtual void deleteRecord( OperationContext* txn, const DiskLoc& dl ) = 0;
virtual StatusWith insertRecord( OperationContext* txn,
const char* data,
int len,
bool enforceQuota ) = 0;
virtual StatusWith insertRecord( OperationContext* txn,
const DocWriter* doc,
bool enforceQuota ) = 0;
/**
* @param notifier - this is called if the document is moved
* it is to be called after the document has been written to new
* location, before deleted from old.
* @return Status or DiskLoc, DiskLoc might be different
*/
virtual StatusWith updateRecord( OperationContext* txn,
const DiskLoc& oldLocation,
const char* data,
int len,
bool enforceQuota,
UpdateMoveNotifier* notifier ) = 0;
virtual Status updateWithDamages( OperationContext* txn,
const DiskLoc& loc,
const RecordData& oldRec,
const char* damageSource,
const mutablebson::DamageVector& damages ) = 0;
/**
* returned iterator owned by caller
* Default arguments return all items in record store.
*/
virtual RecordIterator* getIterator( OperationContext* txn,
const DiskLoc& start = DiskLoc(),
const CollectionScanParams::Direction& dir =
CollectionScanParams::FORWARD
) const = 0;
/**
* Constructs an iterator over a potentially corrupted store, which can be used to salvage
* damaged records. The iterator might return every record in the store if all of them
* are reachable and not corrupted.
*/
virtual RecordIterator* getIteratorForRepair( OperationContext* txn ) const = 0;
/**
* Returns many iterators that partition the RecordStore into many disjoint sets. Iterating
* all returned iterators is equivalent to Iterating the full store.
*/
virtual std::vector getManyIterators( OperationContext* txn ) const = 0;
// higher level
/**
* removes all Records
*/
virtual Status truncate( OperationContext* txn ) = 0;
/**
* Truncate documents newer than the document at 'end' from the capped
* collection. The collection cannot be completely emptied using this
* function. An assertion will be thrown if that is attempted.
* @param inclusive - Truncate 'end' as well iff true
* XXX: this will go away soon, just needed to move for now
*/
virtual void temp_cappedTruncateAfter(OperationContext* txn,
DiskLoc end,
bool inclusive) = 0;
// does this RecordStore support the compact operation
virtual bool compactSupported() const = 0;
virtual Status compact( OperationContext* txn,
RecordStoreCompactAdaptor* adaptor,
const CompactOptions* options,
CompactStats* stats ) = 0;
/**
* @param full - does more checks
* @param scanData - scans each document
* @return OK if the validate run successfully
* OK will be returned even if corruption is found
* deatils will be in result
*/
virtual Status validate( OperationContext* txn,
bool full, bool scanData,
ValidateAdaptor* adaptor,
ValidateResults* results, BSONObjBuilder* output ) const = 0;
/**
* @param scaleSize - amount by which to scale size metrics
* appends any custom stats from the RecordStore or other unique stats
*/
virtual void appendCustomStats( OperationContext* txn,
BSONObjBuilder* result,
double scale ) const = 0;
/**
* Load all data into cache.
* What cache depends on implementation.
* @param output (optional) - where to put detailed stats
*/
virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const = 0;
/**
* @return Status::OK() if option hanlded
* InvalidOptions is option not supported
* other errors indicate option supported, but error setting
*/
virtual Status setCustomOption( OperationContext* txn,
const BSONElement& option,
BSONObjBuilder* info = NULL ) = 0;
protected:
std::string _ns;
};
class RecordStoreCompactAdaptor {
public:
virtual ~RecordStoreCompactAdaptor(){}
virtual bool isDataValid( const RecordData& recData ) = 0;
virtual size_t dataSize( const RecordData& recData ) = 0;
virtual void inserted( const RecordData& recData, const DiskLoc& newLocation ) = 0;
};
struct ValidateResults {
ValidateResults() {
valid = true;
}
bool valid;
std::vector errors;
};
/**
* This is so when a RecordStore is validating all records
* it can call back to someone to check if a record is valid.
* The actual data contained in a Record is totally opaque to the implementation.
*/
class ValidateAdaptor {
public:
virtual ~ValidateAdaptor(){}
virtual Status validate( const RecordData& recordData, size_t* dataSize ) = 0;
};
}