41.1 SegmentBeingWrittenInMemory
SegmentBeingWrittenInMemory is concerned with tracking the write position of the current segment
being prepared in memory. It also is responsible for writing the flush unit headers.
There is a concept of opening a flush unit (which means that some members of the header are initialised, and the write position is offset past the header, ready to write log records for the flush unit payload.
A flush unit must be closed before the next one is opened. When a flush unit is closed the size of the payload and the CRC can be written to the flush unit header.
Write position
The following two members are zero based offsets into the current segment being prepared in memory
int startPositionOfFlushUnit_;
int writePosition_;
startPositionOfFlushUnit_ will always be a multiple of the disk sector size. It locates the
current flush unit.
writePosition_ will never be less than startPositionOfFlushUnit_.
If writePosition_ equals startPositionOfFlushUnit_, then we must have closed the last flush unit,
and we haven't opened the next one. In fact, it is allowable for
writePosition_ = startPositionOfFlushUnit_ = LSS segment size
which means that the current segment is full, and to open a new flush unit we will need to allocate a fresh segment.
Interface to the SegmentWriter
The thread writing to the segment in memory will write to the buffer at the current write position represented by
int writePosition_;
This of course assumes that the current flush unit has already been opened.
After writing data to a flush unit, the segment writer may want to close the flush unit (in order to make the LRS flushable, or because the segment is full). In that case just after closing the flush unit, it immediately opens a new one, in preparation for continued writing to the log.
This means that the SegmentWriter will always see a currently open flush unit.
Check Point Id and FSN
Each flush unit stores a check point id and a 32 bit Flush Sequence Number (FSN). The check point is a guid that is generated each time a check point is performed.
Consider the following depiction of the log broken up into log flush units (LFUs)
Note the following
-
An LFU stores the identity of the last completed check point. The LFUs written while
check point
cpid2is being made therefore still containcpid1. -
After the last check-point LFU is closed, the LSS records the boundary shown by the dotted line
as
positionOfLastCheckPoint_. ThisLogRecordPositionis written into the new root-block division. -
The open, empty LFU immediately after that position is then changed to
cpid2, and its FSN is reset to 1. Later LFUs increment the FSN. -
If the preceding LFU exactly fills a segment, the stored position is the end of that segment;
logically it is still the dotted boundary before the first
cpid2LFU.
When to calculate the CRC
A previous design used the LazyWriter to calculate the CRC on each flush unit before it was written to disk. However, this caused a bug with the cleaner, which needs to be able to iterate through the flush units of segments in memory that haven't yet been written to disk (and had their CRC calculated).
Therefore, the current design calculates the CRC of each flush unit as soon as it is closed by the segment writer.
Code
class SegmentBeingWrittenInMemory
{
public:
SegmentBeingWrittenInMemory(LSS& lss);
~SegmentBeingWrittenInMemory();
void Clear();
void Initialise(RecoveryScanInfo& rsi);
void SetCheckPointId(const Guid& checkPointId);
void StartFlushUnitOnNewSegment(Segment* s, SegId nextSegid);
bool StartAnotherFlushUnit(LogRecordPosition& flushPosition, bool& needToStartANewSegment);
SegId GetNextSegId() const { return nextSegid_; }
Segment* GetSegment() const { return segment_; }
LogRecordPosition GetWritePosAsLogRecordPosition() const
SegId GetSegId() const
int GetNumFreeBytes() const
void OffsetWritePos(int offset)
void WriteData(const void* buffer, int numBytes)
octet_t* GetBufferPtrAtWritePosition()
void SetWritePosFromBufferPtr(const octet_t* p)
private:
void OpenFlushUnit();
bool CloseCurrentNonEmptyFlushUnit();
private:
LSS& lss_;
Guid checkPointId_;
FlushSeqNumber fsn_;
SegId nextSegid_;
Segment* segment_;
int diskSectorSize_;
octet_t* buffer_;
int startPositionOfFlushUnit_;
int writePosition_;
};