38.1 MSSN
The LSS persists a counter called the MSSN (Missing Shutdown Sequence Number) for the number of times the store has been opened and found it was not previously shut down gracefully.
struct ILogStructuredStore
{
// Returns the number of times the store has not been gracefully shut down over its entire life
virtual MSSN GetMissingShutdownSeqNum() const = 0;
...
};
This feature is implemented by:
- Splitting he root block into two parts that can be written independently
because they occupy distinct disk sectors.
- One part is called the static part and is written during check points
- The other part is called the dynamic part and is written when the store is created or opened and when it is closed.
- persisting a gracefulShutdown flag in the dynamic part of the root block
- persisting the MSSN in the root block divisions.
While a store is in normal use the gracefulShutdown flag in the root block on disk is written with the value false, so if the LSS is not closed correctly it will indicate non-graceful shutdown when it is next reopened. Otherwise if the LSS is closed properly the gracefulShutdown flag in the root block on disk is written with the value true.
The root block is only read when the LSS is opened, and both the static and dynamic parts are read in a single I/O operation.
struct RootBlockHeader
{
void Init(int diskSectorSize, int segmentSize)
{
...
gracefulShutdown_ = false;
}
...
// Indicates whether the LSS was gracefully shutdown the last time it was run
// This is used to detect rollback of the persistent store
bool gracefulShutdown_;
};
void RootBlock::WriteDynamicHeader(bool gsf)
{
RootBlockHeader& header = buffer_->header_;
header.gracefulShutdown_ = gsf;
// Write to disk
...
}
void RootBlock::Read(bool& gracefulShutdown)
{
// Read the entire root block from disk
...
gracefulShutdown = buffer_->header_.gracefulShutdown_;
}
class LSS
{
LSS() : mssn_(0) {}
void Close()
{
if (!readOnly_ && !HaveError())
{
rootBlock_.WriteDynamicHeader(true); // Indicate graceful shutdown
}
...
}
void CreateNewStore()
{
...
rootBlock_.WriteDynamicHeader(false);
}
MSSN GetMissingShutdownSeqNum() const
{
return mssn_;
}
// Missing shutdown sequence number.
// Allows clients to know whether the store has rolled back to an earlier state
MSSN mssn_;
void Recover()
{
bool gracefulShutdown;
rootBlock_.Read(gracefulShutdown);
if (!gracefulShutdown || forceIncrementMSSN)
{
// LSS was not shutdown gracefully.
// Clients that call GetMissingShutdownSeqNum(), and save its value will be able to see
// that the MSSN has been incremented since they last stored its value.
// This tells them that it is possible that the LSS has rolled back to an earlier state.
++mssn_;
}
// Indicate that the LSS is not in a graceful shutdown state (in case there is a power failure etc)
if (!readOnly_)
{
rootBlock_.WriteDynamicHeader(false);
}
...
}
void SerialiseRootBlockDivision(Archive& ar, IInputStream* serialisedRpmRootNode)
{
ar << sut_;
ar.WriteStream(serialisedRpmRootNode);
ar << positionOfLastCheckPoint_
<< mssn_
<< checkPointId_
<< txsn_
<< cpsn_;
}
void DeserialiseRootBlockDivision(InputArchive& ar)
{
...
ar >> sut_
>> rpm_
>> positionOfLastCheckPoint_
>> mssn_
>> checkPointId_;
}
};