8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 20:43:03 +01:00
firebird-mirror/src/jrd/trace/TraceLog.cpp

283 lines
6.3 KiB
C++
Raw Normal View History

2009-02-01 23:07:35 +01:00
/*
* PROGRAM: Firebird Trace Services
* MODULE: TraceLog.cpp
* DESCRIPTION: Trace API shared log file
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Khorsun Vladyslav
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Khorsun Vladyslav <hvlad@users.sourceforge.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
2009-02-02 14:31:20 +01:00
#include "firebird.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_IO_H
2009-02-01 23:07:35 +01:00
#include <io.h>
2009-02-02 14:31:20 +01:00
#endif
2009-02-01 23:07:35 +01:00
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "../../common/StatusArg.h"
#include "../../common/classes/TempFile.h"
#include "../../jrd/common.h"
#include "../../jrd/isc_proto.h"
#include "../../jrd/isc_s_proto.h"
#include "../../jrd/os/path_utils.h"
#include "../../jrd/trace/TraceLog.h"
using namespace Firebird;
namespace Jrd {
/// TraceLogImpl
const size_t MAX_LOG_FILE_SIZE = 1024 * 1024;
const unsigned int MAX_FILE_NUM = (unsigned int) -1;
2009-02-05 15:44:11 +01:00
TraceLogImpl::TraceLogImpl(MemoryPool& pool, const PathName& fileName, bool reader) :
2009-02-01 23:07:35 +01:00
m_baseFileName(pool)
{
m_base = 0;
m_fileNum = 0;
m_fileHandle = -1;
m_reader = reader;
ISC_STATUS_ARRAY status;
ISC_map_file(status, fileName.c_str(), initShMem, this, sizeof(ShMemHeader), &m_handle);
if (!m_base)
{
iscLogStatus("Cannot initialize the shared memory region", status);
2009-02-07 16:20:34 +01:00
status_exception::raise(status);
2009-02-01 23:07:35 +01:00
}
PathUtils::concatPath(m_baseFileName, TempFile::getTempPath(), fileName);
TraceLogGuard guard(this);
if (m_reader)
m_fileNum = 0;
else
m_fileNum = m_base->writeFileNum;
m_fileHandle = openFile(m_fileNum);
}
TraceLogImpl::~TraceLogImpl()
{
::close(m_fileHandle);
if (m_reader)
{
// indicate reader is gone
m_base->readFileNum = MAX_FILE_NUM;
for (; m_fileNum <= m_base->writeFileNum; m_fileNum++)
removeFile(m_fileNum);
}
else if (m_fileNum < m_base->readFileNum) {
removeFile(m_fileNum);
}
const bool readerDone = (m_base->readFileNum == MAX_FILE_NUM);
ISC_STATUS_ARRAY status;
ISC_unmap_file(status, &m_handle);
if (m_reader || readerDone) {
unlink(m_baseFileName.c_str());
2009-02-01 23:07:35 +01:00
}
}
int TraceLogImpl::openFile(int fileNum)
{
PathName fileName;
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
2009-02-02 14:31:20 +01:00
const int oflag = O_CREAT | O_RDWR
2009-02-01 23:07:35 +01:00
#ifdef WIN_NT
2009-02-02 14:31:20 +01:00
| O_BINARY | O_SEQUENTIAL | _O_SHORT_LIVED
2009-02-01 23:07:35 +01:00
#endif
;
const int pflag = S_IREAD | S_IWRITE;
2009-02-02 14:31:20 +01:00
int file = open(fileName.c_str(), oflag, pflag);
2009-02-01 23:07:35 +01:00
return file;
}
int TraceLogImpl::removeFile(int fileNum)
{
PathName fileName;
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
return unlink(fileName.c_str());
2009-02-01 23:07:35 +01:00
}
size_t TraceLogImpl::read(void* buf, size_t size)
{
fb_assert(m_reader);
2009-02-02 15:46:24 +01:00
char* p = (char*) buf;
2009-02-01 23:07:35 +01:00
unsigned int readLeft = size;
while (readLeft)
{
const int reads = ::read(m_fileHandle, p, readLeft);
2009-02-02 15:01:22 +01:00
if (reads == 0)
2009-02-01 23:07:35 +01:00
{
2009-02-02 14:31:20 +01:00
const off_t len = lseek(m_fileHandle, 0, SEEK_CUR);
2009-02-01 23:07:35 +01:00
if (len >= MAX_LOG_FILE_SIZE)
{
// this file was read completely, go to next one
2009-02-01 23:07:35 +01:00
::close(m_fileHandle);
removeFile(m_fileNum);
fb_assert(m_base->readFileNum == m_fileNum);
m_fileNum = ++m_base->readFileNum;
m_fileHandle = openFile(m_fileNum);
}
else
{
2009-02-02 15:01:22 +01:00
// nothing to read, return what we have
2009-02-01 23:07:35 +01:00
break;
}
}
2009-02-02 15:01:22 +01:00
else if (reads > 0)
{
p += reads;
readLeft -= reads;
}
else
{
// io error
system_call_failed::raise("read", errno);
break;
}
2009-02-01 23:07:35 +01:00
}
return (size - readLeft);
}
size_t TraceLogImpl::write(const void* buf, size_t size)
{
fb_assert(!m_reader);
// if reader already gone, don't write anything
if (m_base->readFileNum == MAX_FILE_NUM)
return size;
TraceLogGuard guard(this);
2009-02-02 15:46:24 +01:00
const char* p = (const char*) buf;
2009-02-01 23:07:35 +01:00
unsigned int writeLeft = size;
while (writeLeft)
{
const long len = lseek(m_fileHandle, 0, SEEK_END);
const unsigned int toWrite = MIN(writeLeft, MAX_LOG_FILE_SIZE - len);
if (!toWrite)
{
2009-02-02 15:46:24 +01:00
// While this instance of writer was idle, new log file was created.
// More, if current file was already read by reader, we must delete it.
2009-02-01 23:07:35 +01:00
::close(m_fileHandle);
if (m_fileNum < m_base->readFileNum) {
removeFile(m_fileNum);
}
m_fileNum = m_base->writeFileNum;
m_fileHandle = openFile(m_fileNum);
continue;
}
const int written = ::write(m_fileHandle, p, toWrite);
if (written == -1 || size_t(written) != toWrite)
system_call_failed::raise("write", errno);
2009-02-01 23:07:35 +01:00
p += toWrite;
writeLeft -= toWrite;
if (writeLeft || (len + toWrite == MAX_LOG_FILE_SIZE))
{
::close(m_fileHandle);
m_fileNum = ++m_base->writeFileNum;
m_fileHandle = openFile(m_fileNum);
}
}
return size - writeLeft;
}
size_t TraceLogImpl::getApproxLogSize() const
{
return (m_base->writeFileNum - m_base->readFileNum + 1) *
(MAX_LOG_FILE_SIZE / (1024 * 1024));
}
void TraceLogImpl::checkMutex(const TEXT* string, int state)
{
if (state)
{
TEXT msg[BUFFER_TINY];
sprintf(msg, "TRACE: mutex %s error, status = %d", string, state);
gds__log(msg);
fprintf(stderr, "%s\n", msg);
exit(FINI_ERROR);
}
}
void TraceLogImpl::initShMem(void* arg, SH_MEM_T* shmemData, bool initialize)
{
2009-02-02 15:46:24 +01:00
TraceLogImpl* log = (TraceLogImpl*) arg;
2009-02-01 23:07:35 +01:00
#ifdef WIN_NT
checkMutex("init", ISC_mutex_init(&log->m_mutex, shmemData->sh_mem_name));
#endif
ShMemHeader* const header = (ShMemHeader*) shmemData->sh_mem_address;
log->m_base = header;
if (initialize)
{
header->readFileNum = 0;
header->writeFileNum = 0;
#ifndef WIN_NT
checkMutex("init", ISC_mutex_init(&header->mutex));
#endif
}
}
void TraceLogImpl::lock()
{
#ifdef WIN_NT
checkMutex("lock", ISC_mutex_lock(&m_mutex));
#else
checkMutex("lock", ISC_mutex_lock(&m_base->mutex));
#endif
}
void TraceLogImpl::unlock()
{
#ifdef WIN_NT
checkMutex("unlock", ISC_mutex_unlock(&m_mutex));
#else
checkMutex("unlock", ISC_mutex_unlock(&m_base->mutex));
#endif
}
} // namespace Jrd