mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
Better fix for CORE-5264 - thanks to Vlad
This commit is contained in:
parent
fa9f723cce
commit
bbe640a39c
@ -48,11 +48,8 @@ namespace Jrd
|
||||
{
|
||||
bool Database::onRawDevice() const
|
||||
{
|
||||
#ifdef SUPPORT_RAW_DEVICES
|
||||
return PIO_on_raw_device(dbb_filename);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
const PageSpace* const pageSpace = dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
|
||||
return pageSpace->onRawDevice();
|
||||
}
|
||||
|
||||
string Database::getUniqueFileId() const
|
||||
|
@ -47,7 +47,6 @@ public:
|
||||
USHORT fil_sequence; // Sequence number of file
|
||||
USHORT fil_fudge; // Fudge factor for page relocation
|
||||
int fil_desc;
|
||||
//int *fil_trace; // Trace file, if any
|
||||
Firebird::Mutex fil_mutex;
|
||||
USHORT fil_flags;
|
||||
SCHAR fil_string[1]; // Expanded file name
|
||||
@ -76,7 +75,6 @@ public:
|
||||
USHORT fil_sequence; // Sequence number of file
|
||||
USHORT fil_fudge; // Fudge factor for page relocation
|
||||
HANDLE fil_desc; // File descriptor
|
||||
//int *fil_trace; // Trace file, if any
|
||||
Firebird::RWLock* fil_ext_lock; // file extend lock
|
||||
#ifdef SUPERSERVER_V2
|
||||
Firebird::Mutex fil_mutex;
|
||||
@ -94,6 +92,7 @@ const USHORT FIL_no_fs_cache = 2; // not using file system cache
|
||||
const USHORT FIL_readonly = 4; // file opened in readonly mode
|
||||
const USHORT FIL_sh_write = 8; // file opened in shared write mode
|
||||
const USHORT FIL_no_fast_extend = 16; // file not supports fast extending
|
||||
const USHORT FIL_raw_device = 32; // file is raw device
|
||||
|
||||
// Physical IO trace events
|
||||
|
||||
|
@ -49,6 +49,15 @@
|
||||
#include <linux/falloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_RAW_DEVICES
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef LINUX
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
#endif //SUPPORT_RAW_DEVICES
|
||||
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/os/pio.h"
|
||||
#include "../jrd/ods.h"
|
||||
@ -115,7 +124,7 @@ static const mode_t MASK = 0660;
|
||||
|
||||
#define FCNTL_BROKEN
|
||||
static jrd_file* seek_file(jrd_file*, BufferDesc*, FB_UINT64*, FbStatusVector*);
|
||||
static jrd_file* setup_file(Database*, const PathName&, const int, const bool, const bool);
|
||||
static jrd_file* setup_file(Database*, const PathName&, const int, const bool, const bool, const bool);
|
||||
static void lockDatabaseFile(int& desc, const bool shareMode, const bool temporary,
|
||||
const char* fileName, ISC_STATUS operation);
|
||||
static bool unix_error(const TEXT*, const jrd_file*, ISC_STATUS, FbStatusVector* = NULL);
|
||||
@ -271,7 +280,7 @@ jrd_file* PIO_create(thread_db* tdbb, const PathName& file_name,
|
||||
PathName expanded_name(file_name);
|
||||
ISC_expand_filename(expanded_name, false);
|
||||
|
||||
return setup_file(dbb, expanded_name, desc, false, shareMode);
|
||||
return setup_file(dbb, expanded_name, desc, false, shareMode, !(flag & O_CREAT));
|
||||
}
|
||||
|
||||
|
||||
@ -480,9 +489,42 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize)
|
||||
if (os_utils::fstat(file->fil_desc, &statistics))
|
||||
unix_error("fstat", file, isc_io_access_err);
|
||||
|
||||
const FB_UINT64 length = statistics.st_size;
|
||||
FB_UINT64 length = statistics.st_size;
|
||||
|
||||
return (length + pagesize - 1) / pagesize;
|
||||
#ifdef SUPPORT_RAW_DEVICES
|
||||
if (S_ISCHR(statistics.st_mode) || S_ISBLK(statistics.st_mode))
|
||||
{
|
||||
// This place is highly OS-dependent
|
||||
// Looks like any OS needs own ioctl() to determine raw device size
|
||||
#undef HAS_RAW_SIZE
|
||||
|
||||
#ifdef LINUX
|
||||
#ifdef BLKGETSIZE64
|
||||
if (ioctl(file->fil_desc, BLKGETSIZE64, &length) != 0)
|
||||
#endif /*BLKGETSIZE64*/
|
||||
{
|
||||
unsigned long sectorCount;
|
||||
if (ioctl(file->fil_desc, BLKGETSIZE, §orCount) != 0)
|
||||
unix_error("ioctl(BLKGETSIZE)", file, isc_io_access_err);
|
||||
|
||||
unsigned int sectorSize;
|
||||
if (ioctl(file->fil_desc, BLKSSZGET, §orSize) != 0)
|
||||
unix_error("ioctl(BLKSSZGET)", file, isc_io_access_err);
|
||||
|
||||
length = sectorCount;
|
||||
length *= sectorSize;
|
||||
}
|
||||
#define HAS_RAW_SIZE
|
||||
#endif /*LINUX*/
|
||||
|
||||
#ifndef HAS_RAW_SIZE
|
||||
error: Raw device support for your OS is missing. Fix it or turn off raw device support.
|
||||
#endif
|
||||
#undef HAS_RAW_SIZE
|
||||
}
|
||||
#endif /*SUPPORT_RAW_DEVICES*/
|
||||
|
||||
return length / pagesize;
|
||||
}
|
||||
|
||||
|
||||
@ -675,19 +717,24 @@ jrd_file* PIO_open(thread_db* tdbb,
|
||||
|
||||
// os_utils::posix_fadvise(desc, 0, 0, POSIX_FADV_RANDOM);
|
||||
|
||||
bool raw = false;
|
||||
#ifdef SUPPORT_RAW_DEVICES
|
||||
// At this point the file has successfully been opened in either RW or RO
|
||||
// mode. Check if it is a special file (i.e. raw block device) and if a
|
||||
// valid database is on it. If not, return an error.
|
||||
|
||||
if (PIO_on_raw_device(file_name) && !raw_devices_validate_database(desc, file_name))
|
||||
if (PIO_on_raw_device(file_name))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("open") << Arg::Str(file_name) <<
|
||||
Arg::Gds(isc_io_open_err) << Arg::Unix(ENOENT));
|
||||
raw = true;
|
||||
if (!raw_devices_validate_database(desc, file_name))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("open") << Arg::Str(file_name) <<
|
||||
Arg::Gds(isc_io_open_err) << Arg::Unix(ENOENT));
|
||||
}
|
||||
}
|
||||
#endif // SUPPORT_RAW_DEVICES
|
||||
|
||||
return setup_file(dbb, string, desc, readOnly, shareMode);
|
||||
return setup_file(dbb, string, desc, readOnly, shareMode, raw);
|
||||
}
|
||||
|
||||
|
||||
@ -894,7 +941,8 @@ static jrd_file* setup_file(Database* dbb,
|
||||
const PathName& file_name,
|
||||
const int desc,
|
||||
const bool readOnly,
|
||||
const bool shareMode)
|
||||
const bool shareMode,
|
||||
const bool onRawDev)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -919,6 +967,8 @@ static jrd_file* setup_file(Database* dbb,
|
||||
file->fil_flags |= FIL_readonly;
|
||||
if (shareMode)
|
||||
file->fil_flags |= FIL_sh_write;
|
||||
if (onRawDev)
|
||||
file->fil_flags |= FIL_raw_device;
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
|
124
src/jrd/pag.cpp
124
src/jrd/pag.cpp
@ -2035,66 +2035,15 @@ ULONG PageSpace::maxAlloc()
|
||||
**************************************/
|
||||
const USHORT pageSize = dbb->dbb_page_size;
|
||||
const jrd_file* f = file;
|
||||
ULONG nPages = 0;
|
||||
ULONG nPages = PIO_get_number_of_pages(f, pageSize);
|
||||
|
||||
if (maxPageNumber == 0 && !PIO_on_raw_device(f->fil_string))
|
||||
while (f->fil_next && nPages == f->fil_max_page - f->fil_min_page + 1 + f->fil_fudge)
|
||||
{
|
||||
f = f->fil_next;
|
||||
nPages = PIO_get_number_of_pages(f, pageSize);
|
||||
|
||||
while (f->fil_next && nPages == f->fil_max_page - f->fil_min_page + 1 + f->fil_fudge)
|
||||
{
|
||||
f = f->fil_next;
|
||||
if (PIO_on_raw_device(f->fil_string))
|
||||
{
|
||||
nPages = 0;
|
||||
break;
|
||||
}
|
||||
nPages = PIO_get_number_of_pages(f, pageSize);
|
||||
}
|
||||
|
||||
if (nPages)
|
||||
nPages += f->fil_min_page - f->fil_fudge;
|
||||
}
|
||||
|
||||
if (!nPages)
|
||||
{
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
const ULONG pagesPerPip = dbb->dbb_page_manager.pagesPerPIP;
|
||||
WIN window(pageSpaceID, -1);
|
||||
|
||||
// Find the last page allocated
|
||||
|
||||
for (USHORT sequence = maxPageNumber / pagesPerPip; true; ++sequence)
|
||||
{
|
||||
window.win_page = (!sequence) ? pipFirst : sequence * pagesPerPip - 1;
|
||||
ULONG pipUsed = 0;
|
||||
const page_inv_page* page = NULL;
|
||||
|
||||
for (FB_SIZE_T n = 0; n < tdbb->tdbb_bdbs.getCount(); ++n)
|
||||
{
|
||||
BufferDesc *bdb = tdbb->tdbb_bdbs[n];
|
||||
if (bdb && bdb->isLocked() && bdb->bdb_page == window.win_page && bdb->bdb_buffer)
|
||||
{
|
||||
page = (page_inv_page*)(bdb->bdb_buffer);
|
||||
pipUsed = page->pip_used;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!page)
|
||||
{
|
||||
page = (page_inv_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_pages);
|
||||
pipUsed = page->pip_used;
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
}
|
||||
|
||||
if (pipUsed != pagesPerPip)
|
||||
{
|
||||
nPages = sequence * pagesPerPip + pipUsed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
nPages += f->fil_min_page - f->fil_fudge;
|
||||
|
||||
if (maxPageNumber < nPages)
|
||||
maxPageNumber = nPages;
|
||||
@ -2108,30 +2057,75 @@ ULONG PageSpace::maxAlloc(const Database* dbb)
|
||||
return pgSpace->maxAlloc();
|
||||
}
|
||||
|
||||
bool PageSpace::onRawDevice() const
|
||||
{
|
||||
#ifdef SUPPORT_RAW_DEVICES
|
||||
for (const jrd_file* f = file; f != NULL; f = f->fil_next)
|
||||
{
|
||||
if (f->fil_flags & FIL_raw_device)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ULONG PageSpace::lastUsedPage()
|
||||
{
|
||||
const PageManager& pageMgr = dbb->dbb_page_manager;
|
||||
ULONG pipLast = (maxAlloc() / pageMgr.pagesPerPIP) * pageMgr.pagesPerPIP;
|
||||
ULONG pipLast = pipMaxKnown;
|
||||
bool moveUp = true;
|
||||
|
||||
if (!pipLast)
|
||||
{
|
||||
if (!onRawDevice())
|
||||
{
|
||||
pipLast = (maxAlloc() / pageMgr.pagesPerPIP) * pageMgr.pagesPerPIP;
|
||||
pipLast = pipLast ? pipLast - 1 : pipFirst;
|
||||
moveUp = false;
|
||||
}
|
||||
}
|
||||
|
||||
pipLast = pipLast ? pipLast - 1 : pipFirst;
|
||||
win window(pageSpaceID, pipLast);
|
||||
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
|
||||
while (true)
|
||||
{
|
||||
pag* page = CCH_FETCH(tdbb, &window, LCK_read, pag_undefined);
|
||||
if (page->pag_type == pag_pages)
|
||||
|
||||
if (moveUp)
|
||||
{
|
||||
fb_assert(page->pag_type == pag_pages);
|
||||
|
||||
page_inv_page* pip = (page_inv_page*) page;
|
||||
|
||||
if (pip->pip_used != pageMgr.pagesPerPIP)
|
||||
break;
|
||||
UCHAR lastByte = pip->pip_bits[pageMgr.bytesBitPIP - 1];
|
||||
if (lastByte & 0x80)
|
||||
break;
|
||||
}
|
||||
else if (page->pag_type == pag_pages)
|
||||
break;
|
||||
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
|
||||
if (pipLast > pageMgr.pagesPerPIP)
|
||||
pipLast -= pageMgr.pagesPerPIP;
|
||||
else if (pipLast == pipFirst)
|
||||
return 0; // can't find PIP page !
|
||||
if (moveUp)
|
||||
{
|
||||
if (pipLast == pipFirst)
|
||||
pipLast = pageMgr.pagesPerPIP - 1;
|
||||
else
|
||||
pipLast += pageMgr.pagesPerPIP;
|
||||
}
|
||||
else
|
||||
pipLast = pipFirst;
|
||||
{
|
||||
if (pipLast > pageMgr.pagesPerPIP)
|
||||
pipLast -= pageMgr.pagesPerPIP;
|
||||
else if (pipLast == pipFirst)
|
||||
return 0; // can't find PIP page !
|
||||
else
|
||||
pipLast = pipFirst;
|
||||
}
|
||||
|
||||
window.win_page = pipLast;
|
||||
}
|
||||
@ -2156,10 +2150,10 @@ ULONG PageSpace::lastUsedPage()
|
||||
}
|
||||
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
pipMaxKnown = pipLast;
|
||||
|
||||
if (pipLast == pipFirst)
|
||||
return last_bit + 1;
|
||||
|
||||
return last_bit + pipLast + 1;
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
file = 0;
|
||||
dbb = aDbb;
|
||||
maxPageNumber = 0;
|
||||
pipMaxKnown = 0;
|
||||
}
|
||||
|
||||
~PageSpace();
|
||||
@ -135,9 +136,13 @@ public:
|
||||
ULONG getSCNPageNum(ULONG sequence);
|
||||
static ULONG getSCNPageNum(const Database* dbb, ULONG sequence);
|
||||
|
||||
// is pagespace on raw device
|
||||
bool onRawDevice() const;
|
||||
|
||||
private:
|
||||
ULONG maxPageNumber;
|
||||
Database* dbb;
|
||||
ULONG pipMaxKnown;
|
||||
};
|
||||
|
||||
class PageManager : public pool_alloc<type_PageManager>
|
||||
|
Loading…
Reference in New Issue
Block a user