version 1.15, 2008/12/09 18:47:45
|
version 1.16, 2011/06/16 11:32:03
|
|
|
#include <Pegasus/Common/FileSystem.h> | #include <Pegasus/Common/FileSystem.h> |
#include <Pegasus/Common/Dir.h> | #include <Pegasus/Common/Dir.h> |
#include <Pegasus/Common/CommonUTF.h> | #include <Pegasus/Common/CommonUTF.h> |
|
#include <Pegasus/Common/ReadWriteSem.h> |
#include "InstanceIndexFile.h" | #include "InstanceIndexFile.h" |
#include "InstanceDataFile.h" | #include "InstanceDataFile.h" |
#include "AssocInstTable.h" | #include "AssocInstTable.h" |
|
|
| |
static const Uint32 _MAX_FREE_COUNT = 16; | static const Uint32 _MAX_FREE_COUNT = 16; |
| |
|
#define REPOSITORY_BEGIN_PROGRESS_FILE "begin.progress"; |
|
#define REPOSITORY_COMMIT_PROGRESS_FILE "commit.progress"; |
|
#define REPOSITORY_ROLLBACK_PROGRESS_FILE "rollback.progress"; |
|
|
|
// |
|
// This static variable is used inside "rollbackInstanceTransaction" function |
|
// to determine if it is called from the constructor of "CIMRepository" during |
|
// startup in order to avoid the creation of "rollback.progress" state file |
|
// as it increases the startup time of the cimserver process. |
|
// true => startup |
|
// |
|
static bool startup = true; |
|
|
|
|
static inline String _escapeUtf8FileNameCharacters(const String& fileName) | static inline String _escapeUtf8FileNameCharacters(const String& fileName) |
{ | { |
#ifdef PEGASUS_REPOSITORY_ESCAPE_UTF8 | #ifdef PEGASUS_REPOSITORY_ESCAPE_UTF8 |
|
|
{ | { |
PEG_METHOD_ENTER(TRC_REPOSITORY, "_beginInstanceTransaction"); | PEG_METHOD_ENTER(TRC_REPOSITORY, "_beginInstanceTransaction"); |
| |
|
// Create a state file for the begin instance transaction in the same |
|
// directory where the rollback files will be created for |
|
// index and data file. |
|
// The CIMRepository checks if this file is present during |
|
// its initialization. |
|
// If it is present, it is assumed that the last begin transaction was |
|
// incomplete due to system failure and it removes the rollback files along |
|
// with this state file |
|
|
|
String dirPath = FileSystem::extractFilePath(indexFilePath); |
|
String stateFilePath = dirPath + REPOSITORY_BEGIN_PROGRESS_FILE; |
|
|
|
fstream fs; |
|
|
|
fs.open(stateFilePath.getCString(), ios::out PEGASUS_OR_IOS_BINARY); |
|
|
|
if (!fs) |
|
{ |
|
PEG_METHOD_EXIT(); |
|
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
|
MessageLoaderParms( |
|
"Repository.CIMRepository.BEGIN_FAILED", |
|
"The attempt to begin the transaction failed.")); |
|
} |
|
fs.close(); |
|
|
// | // |
// Begin the transaction (an incomplete transaction will cause | // Begin the transaction (an incomplete transaction will cause |
// a rollback the next time an instance-oriented routine is invoked). | // a rollback the next time an instance-oriented routine is invoked). |
|
|
| |
if (!InstanceIndexFile::beginTransaction(indexFilePath)) | if (!InstanceIndexFile::beginTransaction(indexFilePath)) |
{ | { |
|
// |
|
// Remove the state file |
|
// |
|
FileSystem::removeFile(stateFilePath); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms("Repository.CIMRepository.BEGIN_FAILED", |
MessageLoaderParms( |
"begin failed")); |
"Repository.CIMRepository.BEGIN_FAILED", |
|
"The attempt to begin the transaction failed.")); |
} | } |
| |
if (!InstanceDataFile::beginTransaction(dataFilePath)) | if (!InstanceDataFile::beginTransaction(dataFilePath)) |
{ | { |
|
// |
|
// The creation of the index and data rollback file should be atomic |
|
// So undo the begin transaction of index file in case of error in |
|
// the begin transaction of the data file |
|
// |
|
InstanceIndexFile::undoBeginTransaction(indexFilePath); |
|
|
|
// |
|
// Remove the state file |
|
// |
|
FileSystem::removeFile(stateFilePath); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms("Repository.CIMRepository.BEGIN_FAILED", |
MessageLoaderParms( |
"begin failed")); |
"Repository.CIMRepository.BEGIN_FAILED", |
|
"The attempt to begin the transaction failed.")); |
} | } |
|
// |
|
// Since both the rollback files are created, begin transaction is over. |
|
// So remove the state file for the begin transaction |
|
// |
|
FileSystem::removeFile(stateFilePath); |
|
|
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
|
|
{ | { |
PEG_METHOD_ENTER(TRC_REPOSITORY, "_commitInstanceTransaction"); | PEG_METHOD_ENTER(TRC_REPOSITORY, "_commitInstanceTransaction"); |
| |
|
// Create a state file for the commit instance transaction in the same |
|
// directory where the rollback files are created for index and data file. |
|
// The CIMRepository checks if this file is present during |
|
// its initialization. |
|
// If it is present, it is assumed that the last commit transaction was |
|
// incomplete due to system failure and it removes the rollback files along |
|
// with this state file |
|
|
|
String dirPath = FileSystem::extractFilePath(indexFilePath); |
|
String stateFilePath = dirPath + REPOSITORY_COMMIT_PROGRESS_FILE; |
|
|
|
fstream fs; |
|
|
|
fs.open(stateFilePath.getCString(), ios::out PEGASUS_OR_IOS_BINARY); |
|
|
|
if (!fs) |
|
{ |
|
PEG_METHOD_EXIT(); |
|
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
|
MessageLoaderParms( |
|
"Repository.CIMRepository.COMMIT_FAILED", |
|
"The commit operation failed.")); |
|
} |
|
|
|
fs.close(); |
|
|
|
// |
// | // |
// Commit the transaction by removing the rollback files. | // Commit the transaction by removing the rollback files. |
// | // |
| |
if (!InstanceIndexFile::commitTransaction(indexFilePath)) | if (!InstanceIndexFile::commitTransaction(indexFilePath)) |
{ | { |
|
// |
|
// Remove the state file |
|
// |
|
FileSystem::removeFile(stateFilePath); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms("Repository.CIMRepository.COMMIT_FAILED", |
MessageLoaderParms( |
"commit failed")); |
"Repository.CIMRepository.COMMIT_FAILED", |
|
"The commit operation failed.")); |
} | } |
| |
if (!InstanceDataFile::commitTransaction(dataFilePath)) | if (!InstanceDataFile::commitTransaction(dataFilePath)) |
{ | { |
|
// |
|
// Remove the state file |
|
// |
|
|
|
FileSystem::removeFile(stateFilePath); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms("Repository.CIMRepository.COMMIT_FAILED", |
MessageLoaderParms( |
"commit failed")); |
"Repository.CIMRepository.COMMIT_FAILED", |
|
"The commit operation failed.")); |
} | } |
| |
|
// |
|
// Since both the rollback files are removed, commit transaction is over. |
|
// So remove the state file for the commit transaction |
|
// |
|
FileSystem::removeFile(stateFilePath); |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
|
|
} | } |
| |
// Proceed to rollback logic. | // Proceed to rollback logic. |
|
String dirPath = FileSystem::extractFilePath(indexFilePath); |
|
String stateFilePath = dirPath + REPOSITORY_ROLLBACK_PROGRESS_FILE; |
|
|
|
// |
|
// Check the static variable "startup" to determine if this function is |
|
// called from the constructor of "CIMRepository" during startup. |
|
// If it is true do not create the "rollback.progress" state file. |
|
// |
|
|
|
if (!startup) |
|
{ |
|
// Create a state file for the rollback instance transaction in the same |
|
// directory where the rollback files are created for |
|
// index and data file. |
|
// The CIMRepository checks if this file is present during |
|
// its initialization. |
|
// If it is present, it is assumed that the last rollback transaction |
|
// was incomplete due to system failure. So it completes |
|
// the rollback instance transaction and removes this state file |
|
|
|
fstream fs; |
|
|
|
fs.open(stateFilePath.getCString(), ios::out PEGASUS_OR_IOS_BINARY); |
|
|
|
if (!fs) |
|
{ |
|
PEG_METHOD_EXIT(); |
|
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
|
MessageLoaderParms( |
|
"Repository.CIMRepository.ROLLBACK_FAILED", |
|
"The rollback operation failed.")); |
|
} |
|
|
|
fs.close(); |
|
} |
| |
if (!InstanceIndexFile::rollbackTransaction(indexFilePath)) | if (!InstanceIndexFile::rollbackTransaction(indexFilePath)) |
{ | { |
|
if(!startup) |
|
{ |
|
// Remove the state file |
|
FileSystem::removeFile(stateFilePath); |
|
} |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms("Repository.CIMRepository.ROLLBACK_FAILED", |
MessageLoaderParms( |
"rollback failed")); |
"Repository.CIMRepository.ROLLBACK_FAILED", |
|
"The rollback operation failed.")); |
} | } |
| |
if (!InstanceDataFile::rollbackTransaction(dataFilePath)) | if (!InstanceDataFile::rollbackTransaction(dataFilePath)) |
{ | { |
|
if(!startup) |
|
{ |
|
// Remove the state file |
|
FileSystem::removeFile(stateFilePath); |
|
} |
|
|
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, | throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED, |
MessageLoaderParms( | MessageLoaderParms( |
"Repository.CIMRepository.ROLLBACK_FAILED", | "Repository.CIMRepository.ROLLBACK_FAILED", |
"rollback failed")); |
"The rollback operation failed.")); |
|
} |
|
|
|
if (!startup) |
|
{ |
|
// Since both the rollback files are removed, |
|
// rollback transaction is over. |
|
// So remove the state file for the rollback transaction |
|
FileSystem::removeFile(stateFilePath); |
} | } |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// FileBasedStore::_completeTransactions() |
|
// |
|
// Searches for state file in the "instance" directory of all |
|
// namespaces. |
|
// i) Removes the rollback files to void a begin operation. |
|
// ii) Removes the rollback files to complete a commit operation. |
|
// iii) Restores instance index and data files complete a rollback |
|
// operation. |
|
// If no state files are present, this method returns false |
|
// |
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
Boolean FileBasedStore::_completeTransactions() |
|
{ |
|
PEG_METHOD_ENTER(TRC_REPOSITORY, |
|
"FileBasedStore::_completeTransactions"); |
|
|
|
for (Dir dir(_repositoryPath); dir.more(); dir.next()) |
|
{ |
|
String nameSpaceDirName = dir.getName(); |
|
if ((nameSpaceDirName == "..") || |
|
(nameSpaceDirName == ".") || |
|
(nameSpaceDirName == _CONFIGFILE_NAME)) |
|
{ |
|
continue; |
|
} |
|
|
|
String nameSpacePath = _repositoryPath + "/" + nameSpaceDirName; |
|
String nameSpaceName = _dirNameToNamespaceName(nameSpaceDirName); |
|
|
|
if (!FileSystem::isDirectory(nameSpacePath + _CLASSES_SUFFIX) || |
|
!FileSystem::isDirectory(nameSpacePath + _INSTANCES_SUFFIX) || |
|
!FileSystem::isDirectory(nameSpacePath + _QUALIFIERS_SUFFIX)) |
|
{ |
|
PEG_TRACE((TRC_REPOSITORY, Tracer::LEVEL2, |
|
"Namespace: %s ignored -- " |
|
"subdirectories are not correctly formed", |
|
(const char*)nameSpaceDirName.getCString())); |
|
continue; |
|
} |
|
|
|
// |
|
// Get the instance directory path |
|
// |
|
String dirPath = nameSpacePath + _INSTANCES_SUFFIX; |
|
String classesPath = nameSpacePath + _CLASSES_SUFFIX; |
|
|
|
// |
|
// Get the paths of the state files |
|
// |
|
String beginFilePath=dirPath+"/"+REPOSITORY_BEGIN_PROGRESS_FILE; |
|
String commitFilePath=dirPath+"/"+REPOSITORY_COMMIT_PROGRESS_FILE; |
|
String rollbackfilePath=dirPath+"/"+REPOSITORY_ROLLBACK_PROGRESS_FILE; |
|
|
|
Array<String> classNames; |
|
|
|
for (Dir dir(classesPath); dir.more(); dir.next()) |
|
{ |
|
String fileName = dir.getName(); |
|
// Ignore the current and parent directories. |
|
if (fileName == "." || fileName == "..") |
|
continue; |
|
|
|
Uint32 dot = fileName.find('.'); |
|
|
|
// Ignore files without dots in them: |
|
if (dot == PEG_NOT_FOUND) |
|
{ |
|
continue; |
|
} |
|
String className = |
|
_unescapeUtf8FileNameCharacters(fileName.subString(0, dot)); |
|
classNames.append(className); |
|
} |
|
|
|
if(FileSystem::exists(beginFilePath)) |
|
{ |
|
// |
|
// Either the begin or the commit operation is left incomplete |
|
// Begin -> Actual repository update operation is not started. |
|
// Commit -> Actual repository update operation is complete. |
|
// |
|
for (Uint32 j = 0; j < classNames.size(); j++) |
|
{ |
|
// |
|
// Get paths of index and data files: |
|
// |
|
|
|
String indexFilePath = _getInstanceIndexFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
String dataFilePath = _getInstanceDataFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
InstanceIndexFile::undoBeginTransaction(indexFilePath); |
|
InstanceDataFile::undoBeginTransaction(dataFilePath); |
|
} |
|
|
|
FileSystem::removeFile(beginFilePath); |
|
|
|
PEG_METHOD_EXIT(); |
|
return true; |
|
} |
|
|
|
if(FileSystem::exists(commitFilePath)) |
|
{ |
|
// |
|
// Either the begin or the commit operation is left incomplete |
|
// Begin -> Actual repository update operation is not started. |
|
// Commit -> Actual repository update operation is complete. |
|
// In both cases, we can safely remove the rollback files |
|
// |
|
|
|
for (Uint32 j = 0; j < classNames.size(); j++) |
|
{ |
|
// |
|
// Get paths of index and data files: |
|
// |
|
|
|
String indexFilePath = _getInstanceIndexFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
String dataFilePath = _getInstanceDataFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
InstanceIndexFile::commitTransaction(indexFilePath); |
|
InstanceDataFile::commitTransaction(dataFilePath); |
|
} |
|
|
|
FileSystem::removeFile(commitFilePath); |
|
|
|
PEG_METHOD_EXIT(); |
|
return true; |
|
} |
|
|
|
if(FileSystem::exists(rollbackfilePath)) |
|
{ |
|
// Rollback transaction is left incomplete |
|
// Rollback -> Call rollback |
|
|
|
for (Uint32 j = 0; j < classNames.size(); j++) |
|
{ |
|
// Get paths of index and data files: |
|
String indexFilePath = _getInstanceIndexFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
String dataFilePath = _getInstanceDataFilePath( |
|
nameSpaceName, classNames[j]); |
|
|
|
_rollbackInstanceTransaction(indexFilePath, dataFilePath); |
|
} |
|
|
|
FileSystem::removeFile(rollbackfilePath); |
|
|
|
PEG_METHOD_EXIT(); |
|
return true; |
|
} |
|
} |
|
|
|
PEG_METHOD_EXIT(); |
|
return false; |
|
} |
|
|
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
// | // |
// InstanceTransactionHandler | // InstanceTransactionHandler |
|
|
} | } |
} | } |
| |
|
// |
|
// Check if any state files are present in the repository. |
|
// and bring the repository to a consistent state based |
|
// on the particular state file found. |
|
// |
|
if (!_completeTransactions()) |
|
{ |
|
// |
|
// No state files are found in the repository. So, try to |
|
// rollback any incomplete transactions in the repository |
|
// |
_rollbackIncompleteTransactions(); | _rollbackIncompleteTransactions(); |
|
} |
|
|
|
// |
|
// Reset the variable "startup" to false to indicate the |
|
// end of CIMRepository constructor |
|
// |
|
startup = false; |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |