mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Merge pull request #8106 from FirebirdSQL/work/gh-8105
All checks were successful
continuous-integration/drone Build is passing
All checks were successful
continuous-integration/drone Build is passing
Fix for #8105: Master database could miss replication segments on Windows Classic Server
This commit is contained in:
commit
2d9e4792c5
@ -79,8 +79,6 @@ namespace
|
||||
const char* PATHNAME_WILDCARD = "$(pathname)";
|
||||
const char* ARCHPATHNAME_WILDCARD = "$(archivepathname)";
|
||||
|
||||
SegmentHeader g_dummyHeader;
|
||||
|
||||
static THREAD_ENTRY_DECLARE archiver_thread(THREAD_ENTRY_PARAM arg)
|
||||
{
|
||||
ChangeLog* const log = static_cast<ChangeLog*>(arg);
|
||||
@ -97,12 +95,12 @@ namespace
|
||||
#endif
|
||||
}
|
||||
|
||||
void raiseIOError(const char* syscall, const char* filename)
|
||||
void raiseIOError(const char* syscall, const char* filename, ISC_STATUS errcode)
|
||||
{
|
||||
Arg::Gds temp(isc_io_error);
|
||||
temp << Arg::Str(syscall);
|
||||
temp << Arg::Str(filename);
|
||||
temp << SYS_ERR(ERRNO);
|
||||
temp << SYS_ERR(errcode);
|
||||
temp.raise();
|
||||
}
|
||||
}
|
||||
@ -113,10 +111,12 @@ namespace
|
||||
ChangeLog::Segment::Segment(MemoryPool& pool, const PathName& filename, int handle)
|
||||
: m_filename(pool, filename), m_handle(handle)
|
||||
{
|
||||
memset(&m_builtinHeader, 0, sizeof(SegmentHeader));
|
||||
|
||||
struct stat stats;
|
||||
if (fstat(m_handle, &stats) < 0 || stats.st_size < (int) sizeof(SegmentHeader))
|
||||
{
|
||||
m_header = &g_dummyHeader;
|
||||
m_header = &m_builtinHeader;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -125,10 +125,11 @@ ChangeLog::Segment::Segment(MemoryPool& pool, const PathName& filename, int hand
|
||||
|
||||
ChangeLog::Segment::~Segment()
|
||||
{
|
||||
if (m_header != &g_dummyHeader)
|
||||
if (m_header != &m_builtinHeader)
|
||||
unmapHeader();
|
||||
|
||||
::close(m_handle);
|
||||
if (m_handle != -1)
|
||||
::close(m_handle);
|
||||
}
|
||||
|
||||
void ChangeLog::Segment::init(FB_UINT64 sequence, const Guid& guid)
|
||||
@ -168,8 +169,10 @@ bool ChangeLog::Segment::validate(const Guid& guid) const
|
||||
|
||||
void ChangeLog::Segment::copyTo(const PathName& filename) const
|
||||
{
|
||||
fb_assert(m_header != &m_builtinHeader);
|
||||
|
||||
if (os_utils::lseek(m_handle, 0, SEEK_SET) != 0)
|
||||
raiseIOError("seek", m_filename.c_str());
|
||||
raiseIOError("seek", m_filename.c_str(), ERRNO);
|
||||
|
||||
const auto totalLength = m_header->hdr_length;
|
||||
fb_assert(totalLength > sizeof(SegmentHeader));
|
||||
@ -188,16 +191,20 @@ void ChangeLog::Segment::copyTo(const PathName& filename) const
|
||||
|
||||
if (::read(m_handle, data, length) != length)
|
||||
{
|
||||
const ISC_STATUS errcode = ERRNO;
|
||||
|
||||
dstFile.release();
|
||||
unlink(filename.c_str());
|
||||
raiseIOError("read", m_filename.c_str());
|
||||
raiseIOError("read", m_filename.c_str(), errcode);
|
||||
}
|
||||
|
||||
if (::write(dstFile, data, length) != length)
|
||||
{
|
||||
const ISC_STATUS errcode = ERRNO;
|
||||
|
||||
dstFile.release();
|
||||
unlink(filename.c_str());
|
||||
raiseIOError("write", filename.c_str());
|
||||
raiseIOError("write", filename.c_str(), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,6 +213,7 @@ void ChangeLog::Segment::copyTo(const PathName& filename) const
|
||||
|
||||
void ChangeLog::Segment::append(ULONG length, const UCHAR* data)
|
||||
{
|
||||
fb_assert(m_header != &m_builtinHeader);
|
||||
fb_assert(m_header->hdr_state == SEGMENT_STATE_USED);
|
||||
fb_assert(length);
|
||||
|
||||
@ -225,10 +233,36 @@ void ChangeLog::Segment::setState(SegmentState state)
|
||||
const auto full = (state == SEGMENT_STATE_FULL);
|
||||
m_header->hdr_state = state;
|
||||
flush(full);
|
||||
|
||||
if ((state == SEGMENT_STATE_FREE) && (m_header != &m_builtinHeader))
|
||||
closeFile();
|
||||
}
|
||||
|
||||
void ChangeLog::Segment::closeFile()
|
||||
{
|
||||
if (m_header == &m_builtinHeader)
|
||||
{
|
||||
fb_assert(m_handle == -1);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&m_builtinHeader, m_header, sizeof(SegmentHeader));
|
||||
|
||||
unmapHeader();
|
||||
|
||||
if (m_handle != -1)
|
||||
{
|
||||
::close(m_handle);
|
||||
m_handle = -1;
|
||||
}
|
||||
|
||||
m_header = &m_builtinHeader;
|
||||
}
|
||||
|
||||
void ChangeLog::Segment::truncate()
|
||||
{
|
||||
fb_assert(m_header != &m_builtinHeader);
|
||||
|
||||
const auto length = m_header->hdr_length;
|
||||
|
||||
unmapHeader();
|
||||
@ -877,6 +911,18 @@ void ChangeLog::initSegments()
|
||||
if (segment->getSequence() > state->sequence)
|
||||
segment->setState(SEGMENT_STATE_FREE);
|
||||
|
||||
if (segment->getState() == SEGMENT_STATE_FREE)
|
||||
{
|
||||
segment->closeFile();
|
||||
|
||||
if (segment->getSequence() + m_config->segmentCount <= state->sequence)
|
||||
{
|
||||
const PathName& fname = segment->getPathName();
|
||||
unlink(fname.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
segment->addRef();
|
||||
m_segments.add(segment.release());
|
||||
}
|
||||
@ -893,7 +939,7 @@ void ChangeLog::clearSegments()
|
||||
ChangeLog::Segment* ChangeLog::createSegment()
|
||||
{
|
||||
const auto state = m_sharedMemory->getHeader();
|
||||
const auto sequence = ++state->sequence;
|
||||
const auto sequence = state->sequence + 1;
|
||||
|
||||
PathName filename;
|
||||
filename.printf(FILENAME_PATTERN, m_config->filePrefix.c_str(), sequence);
|
||||
@ -901,7 +947,8 @@ ChangeLog::Segment* ChangeLog::createSegment()
|
||||
|
||||
const auto fd = os_utils::openCreateSharedFile(filename.c_str(), O_EXCL | O_BINARY);
|
||||
|
||||
if (::write(fd, &g_dummyHeader, sizeof(SegmentHeader)) != sizeof(SegmentHeader))
|
||||
SegmentHeader dummyHeader = {0};
|
||||
if (::write(fd, &dummyHeader, sizeof(SegmentHeader)) != sizeof(SegmentHeader))
|
||||
{
|
||||
::close(fd);
|
||||
raiseError("Journal file %s write failed (error %d)", filename.c_str(), ERRNO);
|
||||
@ -914,6 +961,7 @@ ChangeLog::Segment* ChangeLog::createSegment()
|
||||
|
||||
m_segments.add(segment);
|
||||
state->generation++;
|
||||
state->sequence++;
|
||||
|
||||
return segment;
|
||||
}
|
||||
@ -939,7 +987,7 @@ ChangeLog::Segment* ChangeLog::reuseSegment(ChangeLog::Segment* segment)
|
||||
// Increase the sequence
|
||||
|
||||
const auto state = m_sharedMemory->getHeader();
|
||||
const auto sequence = ++state->sequence;
|
||||
const auto sequence = state->sequence + 1;
|
||||
|
||||
// Attempt to rename the backing file
|
||||
|
||||
@ -950,7 +998,18 @@ ChangeLog::Segment* ChangeLog::reuseSegment(ChangeLog::Segment* segment)
|
||||
// If renaming fails, then we just create a new file.
|
||||
// The old segment will be reused later in this case.
|
||||
if (::rename(orgname.c_str(), newname.c_str()) < 0)
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
const auto err = ERRNO;
|
||||
|
||||
string warn;
|
||||
warn.printf("Journal file %s rename to %s failed (error %d)",
|
||||
orgname.c_str(), newname.c_str(), err);
|
||||
|
||||
logPrimaryWarning(m_config->dbName, warn);
|
||||
#endif
|
||||
return createSegment();
|
||||
}
|
||||
|
||||
// Re-open the segment using a new name and initialize it
|
||||
|
||||
@ -963,6 +1022,7 @@ ChangeLog::Segment* ChangeLog::reuseSegment(ChangeLog::Segment* segment)
|
||||
|
||||
m_segments.add(segment);
|
||||
state->generation++;
|
||||
state->sequence++;
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
@ -181,6 +181,8 @@ namespace Replication
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
void closeFile();
|
||||
|
||||
private:
|
||||
void mapHeader();
|
||||
void unmapHeader();
|
||||
@ -188,6 +190,7 @@ namespace Replication
|
||||
Firebird::PathName m_filename;
|
||||
int m_handle;
|
||||
SegmentHeader* m_header;
|
||||
SegmentHeader m_builtinHeader; // used by free segments when there is no mapping
|
||||
|
||||
#ifdef WIN_NT
|
||||
HANDLE m_mapping;
|
||||
|
Loading…
Reference in New Issue
Block a user