8
0
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:
AlexPeshkoff 2016-07-28 18:16:09 +03:00
parent fa9f723cce
commit bbe640a39c
5 changed files with 126 additions and 81 deletions

View File

@ -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

View File

@ -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

View File

@ -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, &sectorCount) != 0)
unix_error("ioctl(BLKGETSIZE)", file, isc_io_access_err);
unsigned int sectorSize;
if (ioctl(file->fil_desc, BLKSSZGET, &sectorSize) != 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&)
{

View File

@ -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;
}

View File

@ -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>