📄 transactionalramdirectory.cpp
字号:
/*------------------------------------------------------------------------------
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
*
* Distributable under the terms of either the Apache License (Version 2.0) or
* the GNU Lesser General Public License, as specified in the COPYING file.
------------------------------------------------------------------------------*/
#include "CLucene/StdHeader.h"
#include "TransactionalRAMDirectory.h"
CL_NS_DEF(store)
CL_NS_USE(util)
TransactionalRAMDirectory::TransactionalRAMDirectory():
RAMDirectory(),
filesToRestoreOnAbort(true,true)
{
transOpen = false;
}
TransactionalRAMDirectory::~TransactionalRAMDirectory(){
}
bool TransactionalRAMDirectory::archiveOrigFileIfNecessary(const char* name) {
// If a file named $name was present when the transaction started and the
// original RAMFile object has not been archived for restoration upon
// transaction abort, then do so, and return true.
// In any other case, return false.
if (fileExists(name) && filesToRemoveOnAbort.find(name) == filesToRemoveOnAbort.end()) {
// The file exists, but isn't recorded as having been created after the
// start of the transaction, so it must've been present at the start of
// the transaction.
// Transfer memory ownership of both the key and the value from files to
// filesToRestoreOnAbort.
const char* origName = files.getKey(name);
RAMFile* origFile = files.get(name);
files.remove(name, true, true);
filesToRestoreOnAbort.put(origName, origFile);
CND_CONDITION(!fileExists(name), "File should not exist immediately after archival.");
return true;
}
return false;
}
void TransactionalRAMDirectory::unarchiveOrigFile(const char* name) {
const char* origName = filesToRestoreOnAbort.getKey(name);
if (origName == NULL) {
_CLTHROWA(CL_ERR_RAMTransaction,"File submitted for unarchival was not archived.");
}
RAMFile* origFile = filesToRestoreOnAbort.get(name);
// Transfer memory ownership back to files from filesToRestoreOnAbort.
filesToRestoreOnAbort.remove(name, true, true);
files.put(origName, origFile);
}
bool TransactionalRAMDirectory::transIsOpen() const {
return transOpen;
}
void TransactionalRAMDirectory::transStart() {
if (transOpen) {
_CLTHROWA(CL_ERR_RAMTransaction,"Must resolve previous transaction before starting another.");
}
CND_CONDITION(filesToRemoveOnAbort.size() == 0,
"filesToRemoveOnAbort should have been cleared by either its"
" constructor or transResolved."
);
CND_CONDITION(filesToRestoreOnAbort.size() == 0,
"filesToRestoreOnAbort should have been cleared by either its"
" constructor or transResolved."
);
transOpen = true;
}
void TransactionalRAMDirectory::transResolved() {
// This method implements actions common to both forms of transaction
// resolution.
filesToRemoveOnAbort.clear();
filesToRestoreOnAbort.clear();
transOpen = false;
}
void TransactionalRAMDirectory::transCommit() {
if (!transOpen) {
_CLTHROWA(CL_ERR_RAMTransaction,"There is no open transaction.");
}
// All storage is in memory, so commit is ultra-simple.
transResolved();
}
void TransactionalRAMDirectory::transAbort() {
if (!transOpen) {
_CLTHROWA(CL_ERR_RAMTransaction,"There is no open transaction.");
}
// Delete each file in filesToRemoveOnAbort.
for (FilenameSet::const_iterator itrDel = filesToRemoveOnAbort.begin();
itrDel != filesToRemoveOnAbort.end();
++itrDel
)
{
const char* name = itrDel->first;
size_t nameLength = strlen(name);
// Special exception:
// Refrain from deleting a lock's flag file, as that would interfere with
// the operation of the lock.
if (!(nameLength >= 5 && strcmp(name + nameLength - 5, ".lock"))) {
RAMDirectory::deleteFile(name);
}
}
// Ownership of the memory of both the key and the value never left files,
// so there's no need for a special directive to filesToRemoveOnAbort.
filesToRemoveOnAbort.clear();
// Now that any new-since-trans-start files with the same names as
// already-present-at-trans-start files are out of the way, restore each
// file in filesToRestoreOnAbort.
AStringArrayConst removeTheseWithoutDeletingMem;
for (TransFileMap::const_iterator itr = filesToRestoreOnAbort.begin();
itr != filesToRestoreOnAbort.end();
++itr
)
{
const char* name = itr->first;
files.put(name, itr->second);
// We've just transferred ownership of the memory of both the key and the
// value to files; we must now direct filesToRestoreOnAbort not to delete
// that memory as it removes the entry. This is performed in a separate
// loop to avoid modifying filesToRestoreOnAbort while iterating over it.
removeTheseWithoutDeletingMem.push_back(name);
}
for (AStringArrayConst::iterator itrRem = removeTheseWithoutDeletingMem.begin();
itrRem != removeTheseWithoutDeletingMem.end();
++itrRem
)
{
filesToRestoreOnAbort.remove(*itrRem); //remove iterator
}
CND_CONDITION(filesToRestoreOnAbort.size() == 0, "filesToRestoreOnAbort should be empty.");
transResolved();
}
bool TransactionalRAMDirectory::deleteFile(const char* name) {
if (!transOpen) {
return RAMDirectory::deleteFile(name);
}
bool wasOriginalAndWasArchived = archiveOrigFileIfNecessary(name);
if (!wasOriginalAndWasArchived) {
// The file to be deleted wasn't present at transaction start, so instead
// of archiving it, we delete it the conventional way, making sure to
// erase its record in filesToRemoveOnAbort if it was listed there.
filesToRemoveOnAbort.remove(name);
return RAMDirectory::deleteFile(name);
}
return true;
}
void TransactionalRAMDirectory::renameFile(const char* from, const char* to) {
// During the review on 2005.03.18, decided not to implement transactional
// renameFile for two reasons:
// a) It's not needed in the limited scenario for which
// TransactionalRAMDirectory was designed (IndexWriter::addDocument and
// subcode).
// b) Supporting renaming during a transaction would add considerable
// bookkeeping overhead, reducing the performance of the overwhelmingly
// typical case (commit) in order to support the rare case (abort).
//
// This was not a thinly disguised punt due to the complication of
// implementing renameFile transactionally; rather, several implementations
// were considered, but it seemed wrongheaded to degrade the performance of
// the typical case based on the mere potential need to support renameFile
// at some future point for the benefit of the atypical case.
if (transOpen) {
_CLTHROWA(CL_ERR_RAMTransaction,"TransactionalRAMDirectory disallows renameFile during a transaction.");
}
RAMDirectory::renameFile(from, to);
}
IndexOutput* TransactionalRAMDirectory::createOutput(const char* name) {
if (!transOpen) {
return RAMDirectory::createOutput(name);
}
bool wasOriginalAndWasArchived = archiveOrigFileIfNecessary(name);
try {
IndexOutput* ret = RAMDirectory::createOutput(name);
// Importantly, we store a pointer to the filename memory managed by
// files, rather than that passed in by the client (name). We don't make
// an additional copy of the filename's memory because the transactional
// metadata container filesToRemoveOnAbort is not at risk of outliving
// files.
filesToRemoveOnAbort.put(files.getKey(name),NULL);
return ret;
} catch (...) {
if (wasOriginalAndWasArchived) {
unarchiveOrigFile(name);
}
throw;
}
}
void TransactionalRAMDirectory::close() {
if (transOpen) {
transAbort();
}
RAMDirectory::close();
}
CL_NS_END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -