mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03:03 +01:00
Core support for 32KB page size. Disabled so far.
This commit is contained in:
parent
02120b05d1
commit
6f7185ec14
430
src/jrd/dpm.epp
430
src/jrd/dpm.epp
@ -65,7 +65,7 @@ DATABASE DB = FILENAME "ODS.RDB";
|
|||||||
|
|
||||||
#define DECOMPOSE(n, divisor, q, r) {r = n % divisor; q = n / divisor;}
|
#define DECOMPOSE(n, divisor, q, r) {r = n % divisor; q = n / divisor;}
|
||||||
//#define DECOMPOSE_QUOTIENT(n, divisor, q) {q = n / divisor;}
|
//#define DECOMPOSE_QUOTIENT(n, divisor, q) {q = n / divisor;}
|
||||||
#define HIGH_WATER(x) ((SSHORT) sizeof (data_page) + (SSHORT) sizeof (data_page::dpg_repeat) * (x - 1))
|
#define HIGH_WATER(x) ((USHORT) sizeof (data_page) + (USHORT) sizeof (data_page::dpg_repeat) * (x - 1))
|
||||||
#define SPACE_FUDGE RHDF_SIZE
|
#define SPACE_FUDGE RHDF_SIZE
|
||||||
|
|
||||||
using namespace Jrd;
|
using namespace Jrd;
|
||||||
@ -73,6 +73,7 @@ using namespace Ods;
|
|||||||
using namespace Firebird;
|
using namespace Firebird;
|
||||||
|
|
||||||
static void check_swept(thread_db*, record_param*);
|
static void check_swept(thread_db*, record_param*);
|
||||||
|
static USHORT compress(thread_db*, data_page*);
|
||||||
static void delete_tail(thread_db*, rhdf*, const USHORT, USHORT);
|
static void delete_tail(thread_db*, rhdf*, const USHORT, USHORT);
|
||||||
static void fragment(thread_db*, record_param*, SSHORT, const Compressor&, SSHORT, const jrd_tra*);
|
static void fragment(thread_db*, record_param*, SSHORT, const Compressor&, SSHORT, const jrd_tra*);
|
||||||
static void extend_relation(thread_db*, jrd_rel*, WIN*, const Jrd::RecordStorageType type);
|
static void extend_relation(thread_db*, jrd_rel*, WIN*, const Jrd::RecordStorageType type);
|
||||||
@ -249,14 +250,14 @@ double DPM_cardinality(thread_db* tdbb, jrd_rel* relation, const Format* format)
|
|||||||
(Ods::data_page*) CCH_HANDOFF(tdbb, &window, *page, LCK_read, pag_data);
|
(Ods::data_page*) CCH_HANDOFF(tdbb, &window, *page, LCK_read, pag_data);
|
||||||
recordCount = dpage->dpg_count;
|
recordCount = dpage->dpg_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCH_RELEASE(tdbb, &window);
|
CCH_RELEASE(tdbb, &window);
|
||||||
return (double) recordCount;
|
return (double) recordCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format) {
|
if (!format)
|
||||||
format = relation->rel_current_format;
|
format = relation->rel_current_format;
|
||||||
}
|
|
||||||
|
|
||||||
return (double) dataPages * (dbb->dbb_page_size - DPG_SIZE) /
|
return (double) dataPages * (dbb->dbb_page_size - DPG_SIZE) /
|
||||||
(minRecordSize + (format->fmt_length * 0.5));
|
(minRecordSize + (format->fmt_length * 0.5));
|
||||||
@ -340,9 +341,8 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((org_rpb->rpb_flags & rpb_delta) && temp.rpb_prior) {
|
if ((org_rpb->rpb_flags & rpb_delta) && temp.rpb_prior)
|
||||||
org_rpb->rpb_prior = temp.rpb_prior;
|
org_rpb->rpb_prior = temp.rpb_prior;
|
||||||
}
|
|
||||||
else if (org_rpb->rpb_flags & rpb_delta)
|
else if (org_rpb->rpb_flags & rpb_delta)
|
||||||
{
|
{
|
||||||
CCH_RELEASE(tdbb, &org_rpb->getWindow(tdbb));
|
CCH_RELEASE(tdbb, &org_rpb->getWindow(tdbb));
|
||||||
@ -371,9 +371,8 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
// too small, compute the number of pad bytes required
|
// too small, compute the number of pad bytes required
|
||||||
|
|
||||||
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
||||||
if (fill < 0 || (new_rpb->rpb_flags & rpb_deleted)) {
|
if (fill < 0 || (new_rpb->rpb_flags & rpb_deleted))
|
||||||
fill = 0;
|
fill = 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Accomodate max record size i.e. 64K
|
// Accomodate max record size i.e. 64K
|
||||||
const SLONG length = ROUNDUP(RHD_SIZE + size + fill, ODS_ALIGNMENT);
|
const SLONG length = ROUNDUP(RHD_SIZE + size + fill, ODS_ALIGNMENT);
|
||||||
@ -381,8 +380,8 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
// Find space on page and open slot
|
// Find space on page and open slot
|
||||||
|
|
||||||
USHORT slot = page->dpg_count;
|
USHORT slot = page->dpg_count;
|
||||||
SSHORT space = dbb->dbb_page_size;
|
USHORT space = dbb->dbb_page_size;
|
||||||
SSHORT top = HIGH_WATER(page->dpg_count);
|
USHORT top = HIGH_WATER(page->dpg_count);
|
||||||
SSHORT available = dbb->dbb_page_size - top;
|
SSHORT available = dbb->dbb_page_size - top;
|
||||||
|
|
||||||
USHORT n = 0;
|
USHORT n = 0;
|
||||||
@ -390,9 +389,8 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
for (const data_page::dpg_repeat* const end = index + page->dpg_count;
|
for (const data_page::dpg_repeat* const end = index + page->dpg_count;
|
||||||
index < end; index++, n++)
|
index < end; index++, n++)
|
||||||
{
|
{
|
||||||
if (!index->dpg_length && slot == page->dpg_count) {
|
if (!index->dpg_length && slot == page->dpg_count)
|
||||||
slot = n;
|
slot = n;
|
||||||
}
|
|
||||||
|
|
||||||
if (index->dpg_length && index->dpg_offset)
|
if (index->dpg_length && index->dpg_offset)
|
||||||
{
|
{
|
||||||
@ -424,14 +422,15 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
|
|
||||||
// Record fits, in theory. Check to see if the page needs compression
|
// Record fits, in theory. Check to see if the page needs compression
|
||||||
|
|
||||||
space -= length;
|
if (length > space - top)
|
||||||
if (space < top) {
|
space = compress(tdbb, page);
|
||||||
space = DPM_compress(tdbb, page) - length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot == page->dpg_count) {
|
if (slot == page->dpg_count)
|
||||||
++page->dpg_count;
|
++page->dpg_count;
|
||||||
}
|
|
||||||
|
fb_assert(space >= length);
|
||||||
|
space -= length;
|
||||||
|
fb_assert(space >= top);
|
||||||
|
|
||||||
// Swap the old record into the new slot and the new record into the old slot
|
// Swap the old record into the new slot and the new record into the old slot
|
||||||
|
|
||||||
@ -456,9 +455,8 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
|
|
||||||
dcc.pack(new_rpb->rpb_address, header->rhd_data);
|
dcc.pack(new_rpb->rpb_address, header->rhd_data);
|
||||||
|
|
||||||
if (fill) {
|
if (fill)
|
||||||
memset(header->rhd_data + size, 0, fill);
|
memset(header->rhd_data + size, 0, fill);
|
||||||
}
|
|
||||||
|
|
||||||
if (page->dpg_header.pag_flags & dpg_swept)
|
if (page->dpg_header.pag_flags & dpg_swept)
|
||||||
{
|
{
|
||||||
@ -472,60 +470,6 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int DPM_compress( thread_db* tdbb, data_page* page)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* D P M _ c o m p r e s s
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Compress a data page. Return the high water mark.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
SET_TDBB(tdbb);
|
|
||||||
Database* dbb = tdbb->getDatabase();
|
|
||||||
|
|
||||||
#ifdef VIO_DEBUG
|
|
||||||
VIO_trace(DEBUG_TRACE_ALL,
|
|
||||||
"compress (page)\n");
|
|
||||||
|
|
||||||
VIO_trace(DEBUG_TRACE_ALL_INFO,
|
|
||||||
" sequence %"SLONGFORMAT"\n", page->dpg_sequence);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UCHAR temp_page[MAX_PAGE_SIZE];
|
|
||||||
if (dbb->dbb_page_size > sizeof(temp_page)) {
|
|
||||||
BUGCHECK(250); // msg 250 temporary page buffer too small
|
|
||||||
}
|
|
||||||
SSHORT space = dbb->dbb_page_size;
|
|
||||||
const data_page::dpg_repeat* const end = page->dpg_rpt + page->dpg_count;
|
|
||||||
|
|
||||||
for (data_page::dpg_repeat* index = page->dpg_rpt; index < end; index++)
|
|
||||||
{
|
|
||||||
if (index->dpg_offset)
|
|
||||||
{
|
|
||||||
// 11-Aug-2004. Nickolay Samofatov.
|
|
||||||
// Copy block of pre-aligned length to avoid putting rubbish from stack into database
|
|
||||||
// This should also work just a little bit faster too.
|
|
||||||
const SSHORT l = ROUNDUP(index->dpg_length, ODS_ALIGNMENT);
|
|
||||||
space -= l;
|
|
||||||
memcpy(temp_page + space, (UCHAR *) page + index->dpg_offset, l);
|
|
||||||
index->dpg_offset = space;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((UCHAR *) page + space, temp_page + space, dbb->dbb_page_size - space);
|
|
||||||
|
|
||||||
if (page->dpg_header.pag_type != pag_data) {
|
|
||||||
BUGCHECK(251); // msg 251 damaged data page
|
|
||||||
}
|
|
||||||
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DPM_create_relation( thread_db* tdbb, jrd_rel* relation)
|
void DPM_create_relation( thread_db* tdbb, jrd_rel* relation)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -641,17 +585,18 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation)
|
|||||||
BUGCHECK(243);
|
BUGCHECK(243);
|
||||||
// msg 243 missing pointer page in DPM_data_pages
|
// msg 243 missing pointer page in DPM_data_pages
|
||||||
}
|
}
|
||||||
|
|
||||||
const ULONG* page = ppage->ppg_page;
|
const ULONG* page = ppage->ppg_page;
|
||||||
const ULONG* const end_page = page + ppage->ppg_count;
|
const ULONG* const end_page = page + ppage->ppg_count;
|
||||||
while (page < end_page)
|
while (page < end_page)
|
||||||
{
|
{
|
||||||
if (*page++) {
|
if (*page++)
|
||||||
pages++;
|
pages++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (ppage->ppg_header.pag_flags & ppg_eof) {
|
if (ppage->ppg_header.pag_flags & ppg_eof)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
CCH_RELEASE(tdbb, &window);
|
CCH_RELEASE(tdbb, &window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,11 +769,10 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
|
|||||||
// exclusive access, put a timeout on this fetch to be able to recover from
|
// exclusive access, put a timeout on this fetch to be able to recover from
|
||||||
// possible deadlocks.
|
// possible deadlocks.
|
||||||
page = (data_page*) CCH_FETCH_TIMEOUT(tdbb, window, LCK_write, pag_data, -1);
|
page = (data_page*) CCH_FETCH_TIMEOUT(tdbb, window, LCK_write, pag_data, -1);
|
||||||
if (!page) {
|
if (page)
|
||||||
CCH_RELEASE(tdbb, &pwindow);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
CCH_RELEASE(tdbb, &pwindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page->dpg_count)
|
if (page->dpg_count)
|
||||||
@ -955,9 +899,9 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
count = ppage->ppg_count = ptr - ppage->ppg_page;
|
count = ppage->ppg_count = ptr - ppage->ppg_page;
|
||||||
if (count) {
|
if (count)
|
||||||
count--;
|
count--;
|
||||||
}
|
|
||||||
ppage->ppg_min_space = MIN(ppage->ppg_min_space, count);
|
ppage->ppg_min_space = MIN(ppage->ppg_min_space, count);
|
||||||
|
|
||||||
relPages->rel_slot_space = MIN(relPages->rel_slot_space, pp_sequence);
|
relPages->rel_slot_space = MIN(relPages->rel_slot_space, pp_sequence);
|
||||||
@ -1030,9 +974,8 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
|
|||||||
const pointer_page* ppage =
|
const pointer_page* ppage =
|
||||||
get_pointer_page(tdbb, relation, relPages, &window, sequence, LCK_read);
|
get_pointer_page(tdbb, relation, relPages, &window, sequence, LCK_read);
|
||||||
if (!ppage)
|
if (!ppage)
|
||||||
{
|
|
||||||
BUGCHECK(246); // msg 246 pointer page lost from DPM_delete_relation
|
BUGCHECK(246); // msg 246 pointer page lost from DPM_delete_relation
|
||||||
}
|
|
||||||
const ULONG* page = ppage->ppg_page;
|
const ULONG* page = ppage->ppg_page;
|
||||||
const UCHAR* flags = (UCHAR *) (ppage->ppg_page + dbb->dbb_dp_per_pp);
|
const UCHAR* flags = (UCHAR *) (ppage->ppg_page + dbb->dbb_dp_per_pp);
|
||||||
|
|
||||||
@ -1042,15 +985,15 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
|
|||||||
|
|
||||||
for (USHORT i = 0; i < ppage->ppg_count; i++, page++)
|
for (USHORT i = 0; i < ppage->ppg_count; i++, page++)
|
||||||
{
|
{
|
||||||
if (!*page) {
|
if (!*page)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// if (flags[i >> 2] & (2 << ((i & 3) << 1)))
|
// if (flags[i >> 2] & (2 << ((i & 3) << 1)))
|
||||||
if (PPG_DP_BIT_TEST(flags, i, ppg_dp_large))
|
if (PPG_DP_BIT_TEST(flags, i, ppg_dp_large))
|
||||||
{
|
{
|
||||||
data_window.win_page = *page;
|
data_window.win_page = *page;
|
||||||
data_page* dpage = (data_page*) CCH_FETCH(tdbb, &data_window, LCK_write, pag_data);
|
data_page* dpage = (data_page*) CCH_FETCH(tdbb, &data_window, LCK_write, pag_data);
|
||||||
|
|
||||||
const data_page::dpg_repeat* line = dpage->dpg_rpt;
|
const data_page::dpg_repeat* line = dpage->dpg_rpt;
|
||||||
const data_page::dpg_repeat* const end_line = line + dpage->dpg_count;
|
const data_page::dpg_repeat* const end_line = line + dpage->dpg_count;
|
||||||
for (; line < end_line; line++)
|
for (; line < end_line; line++)
|
||||||
@ -1065,10 +1008,12 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CCH_RELEASE_TAIL(tdbb, &data_window);
|
CCH_RELEASE_TAIL(tdbb, &data_window);
|
||||||
}
|
}
|
||||||
pages.add(*page);
|
pages.add(*page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const UCHAR pag_flags = ppage->ppg_header.pag_flags;
|
const UCHAR pag_flags = ppage->ppg_header.pag_flags;
|
||||||
CCH_RELEASE_TAIL(tdbb, &window);
|
CCH_RELEASE_TAIL(tdbb, &window);
|
||||||
|
|
||||||
@ -1076,10 +1021,8 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
|
|||||||
PAG_release_pages(tdbb, relPages->rel_pg_space_id, pages.getCount(), pages.begin(), 0);
|
PAG_release_pages(tdbb, relPages->rel_pg_space_id, pages.getCount(), pages.begin(), 0);
|
||||||
|
|
||||||
if (pag_flags & ppg_eof)
|
if (pag_flags & ppg_eof)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
delete relPages->rel_pages;
|
delete relPages->rel_pages;
|
||||||
relPages->rel_pages = NULL;
|
relPages->rel_pages = NULL;
|
||||||
@ -1340,13 +1283,9 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val)
|
|||||||
|
|
||||||
window.win_page = (*vector)[sequence];
|
window.win_page = (*vector)[sequence];
|
||||||
window.win_flags = 0;
|
window.win_flags = 0;
|
||||||
generator_page* page;
|
|
||||||
if (dbb->readOnly()) {
|
const SSHORT lock_mode = dbb->readOnly() ? LCK_read : LCK_write;
|
||||||
page = (generator_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_ids);
|
generator_page* const page = (generator_page*) CCH_FETCH(tdbb, &window, lock_mode, pag_ids);
|
||||||
}
|
|
||||||
else {
|
|
||||||
page = (generator_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we are in ODS >= 10, then we have a pointer to an int64 value in the
|
/* If we are in ODS >= 10, then we have a pointer to an int64 value in the
|
||||||
* generator page: if earlier than 10, it's a pointer to a long value.
|
* generator page: if earlier than 10, it's a pointer to a long value.
|
||||||
@ -1364,14 +1303,13 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val)
|
|||||||
CCH_RELEASE(tdbb, &window);
|
CCH_RELEASE(tdbb, &window);
|
||||||
ERR_post(Arg::Gds(isc_read_only_database));
|
ERR_post(Arg::Gds(isc_read_only_database));
|
||||||
}
|
}
|
||||||
|
|
||||||
CCH_MARK_SYSTEM(tdbb, &window);
|
CCH_MARK_SYSTEM(tdbb, &window);
|
||||||
|
|
||||||
if (initialize) {
|
if (initialize)
|
||||||
*ptr = val;
|
*ptr = val;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
*ptr += val;
|
*ptr += val;
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction)
|
if (transaction)
|
||||||
transaction->tra_flags |= TRA_write;
|
transaction->tra_flags |= TRA_write;
|
||||||
@ -1415,18 +1353,17 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type)
|
|||||||
ULONG pp_sequence;
|
ULONG pp_sequence;
|
||||||
USHORT slot, line;
|
USHORT slot, line;
|
||||||
rpb->rpb_number.decompose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, line, slot, pp_sequence);
|
rpb->rpb_number.decompose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, line, slot, pp_sequence);
|
||||||
|
|
||||||
// Check if the record number is OK
|
// Check if the record number is OK
|
||||||
|
|
||||||
if (rpb->rpb_number.getValue() < 0) {
|
if (rpb->rpb_number.getValue() < 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Find the next pointer page, data page, and record
|
// Find the next pointer page, data page, and record
|
||||||
pointer_page* page = get_pointer_page(tdbb, rpb->rpb_relation,
|
pointer_page* page = get_pointer_page(tdbb, rpb->rpb_relation,
|
||||||
rpb->rpb_relation->getPages(tdbb), window, pp_sequence, LCK_read);
|
rpb->rpb_relation->getPages(tdbb), window, pp_sequence, LCK_read);
|
||||||
if (!page) {
|
if (!page)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef VIO_DEBUG
|
#ifdef VIO_DEBUG
|
||||||
VIO_trace(DEBUG_READS_INFO,
|
VIO_trace(DEBUG_READS_INFO,
|
||||||
@ -1507,28 +1444,23 @@ ULONG DPM_get_blob(thread_db* tdbb,
|
|||||||
{
|
{
|
||||||
const ULONG page_number = ppage->ppg_page[slot];
|
const ULONG page_number = ppage->ppg_page[slot];
|
||||||
if (!page_number)
|
if (!page_number)
|
||||||
{
|
|
||||||
goto punt;
|
goto punt;
|
||||||
}
|
|
||||||
|
|
||||||
data_page* page = (data_page*) CCH_HANDOFF(tdbb,
|
data_page* page = (data_page*) CCH_HANDOFF(tdbb,
|
||||||
&rpb.getWindow(tdbb),
|
&rpb.getWindow(tdbb),
|
||||||
page_number,
|
page_number,
|
||||||
(SSHORT) (delete_flag ? LCK_write : LCK_read),
|
(SSHORT) (delete_flag ? LCK_write : LCK_read),
|
||||||
pag_data);
|
pag_data);
|
||||||
if (line >= page->dpg_count) {
|
if (line >= page->dpg_count)
|
||||||
goto punt;
|
goto punt;
|
||||||
}
|
|
||||||
|
|
||||||
data_page::dpg_repeat* index = &page->dpg_rpt[line];
|
data_page::dpg_repeat* index = &page->dpg_rpt[line];
|
||||||
if (index->dpg_offset == 0) {
|
if (index->dpg_offset == 0)
|
||||||
goto punt;
|
goto punt;
|
||||||
}
|
|
||||||
|
|
||||||
blh* header = (blh*) ((SCHAR *) page + index->dpg_offset);
|
blh* header = (blh*) ((SCHAR *) page + index->dpg_offset);
|
||||||
if (!(header->blh_flags & rhd_blob)) {
|
if (!(header->blh_flags & rhd_blob))
|
||||||
goto punt;
|
goto punt;
|
||||||
}
|
|
||||||
|
|
||||||
// We've got the blob header and everything looks ducky. Get the header
|
// We've got the blob header and everything looks ducky. Get the header
|
||||||
// fields.
|
// fields.
|
||||||
@ -1550,13 +1482,11 @@ ULONG DPM_get_blob(thread_db* tdbb,
|
|||||||
blob->blb_flags |= BLB_large_scan;
|
blob->blb_flags |= BLB_large_scan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->blh_flags & rhd_stream_blob) {
|
if (header->blh_flags & rhd_stream_blob)
|
||||||
blob->blb_flags |= BLB_stream;
|
blob->blb_flags |= BLB_stream;
|
||||||
}
|
|
||||||
|
|
||||||
if (header->blh_flags & rhd_damaged) {
|
if (header->blh_flags & rhd_damaged)
|
||||||
goto punt;
|
goto punt;
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the data either into page clump (level 0) or page vector (levels
|
// Retrieve the data either into page clump (level 0) or page vector (levels
|
||||||
// 1 and 2).
|
// 1 and 2).
|
||||||
@ -1616,10 +1546,10 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
// Try to account for staggered execution of large sequential scans.
|
// Try to account for staggered execution of large sequential scans.
|
||||||
|
|
||||||
window->win_scans = rpb->rpb_relation->rel_scan_count - rpb->rpb_org_scans;
|
window->win_scans = rpb->rpb_relation->rel_scan_count - rpb->rpb_org_scans;
|
||||||
if (window->win_scans < 1) {
|
|
||||||
|
if (window->win_scans < 1)
|
||||||
window->win_scans = rpb->rpb_relation->rel_scan_count;
|
window->win_scans = rpb->rpb_relation->rel_scan_count;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
rpb->rpb_prior = NULL;
|
rpb->rpb_prior = NULL;
|
||||||
|
|
||||||
// Find starting point
|
// Find starting point
|
||||||
@ -1657,9 +1587,8 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
{
|
{
|
||||||
const pointer_page* ppage = get_pointer_page(tdbb, rpb->rpb_relation,
|
const pointer_page* ppage = get_pointer_page(tdbb, rpb->rpb_relation,
|
||||||
relPages, window, pp_sequence, LCK_read);
|
relPages, window, pp_sequence, LCK_read);
|
||||||
if (!ppage) {
|
if (!ppage)
|
||||||
BUGCHECK(249); // msg 249 pointer page vanished from DPM_next
|
BUGCHECK(249); // msg 249 pointer page vanished from DPM_next
|
||||||
}
|
|
||||||
|
|
||||||
for (; slot < ppage->ppg_count;)
|
for (; slot < ppage->ppg_count;)
|
||||||
{
|
{
|
||||||
@ -1681,15 +1610,12 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
USHORT slot2 = slot;
|
USHORT slot2 = slot;
|
||||||
USHORT i;
|
USHORT i;
|
||||||
for (i = 0; i < dbb->dbb_prefetch_pages && slot2 < ppage->ppg_count;)
|
for (i = 0; i < dbb->dbb_prefetch_pages && slot2 < ppage->ppg_count;)
|
||||||
{
|
|
||||||
pages[i++] = ppage->ppg_page[slot2++];
|
pages[i++] = ppage->ppg_page[slot2++];
|
||||||
}
|
|
||||||
|
|
||||||
// If no more data pages, piggyback next pointer page.
|
// If no more data pages, piggyback next pointer page.
|
||||||
|
|
||||||
if (slot2 >= ppage->ppg_count) {
|
if (slot2 >= ppage->ppg_count)
|
||||||
pages[i++] = ppage->ppg_next;
|
pages[i++] = ppage->ppg_next;
|
||||||
}
|
|
||||||
|
|
||||||
CCH_PREFETCH(tdbb, pages, i);
|
CCH_PREFETCH(tdbb, pages, i);
|
||||||
}
|
}
|
||||||
@ -1712,18 +1638,16 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
// Prevent large relations from emptying cache. When scrollable
|
// Prevent large relations from emptying cache. When scrollable
|
||||||
// cursors are surfaced, this logic may need to be revisited.
|
// cursors are surfaced, this logic may need to be revisited.
|
||||||
|
|
||||||
if (window->win_flags & WIN_large_scan) {
|
if (window->win_flags & WIN_large_scan)
|
||||||
CCH_RELEASE_TAIL(tdbb, window);
|
CCH_RELEASE_TAIL(tdbb, window);
|
||||||
}
|
|
||||||
else if (window->win_flags & WIN_garbage_collector &&
|
else if (window->win_flags & WIN_garbage_collector &&
|
||||||
window->win_flags & WIN_garbage_collect)
|
window->win_flags & WIN_garbage_collect)
|
||||||
{
|
{
|
||||||
CCH_RELEASE_TAIL(tdbb, window);
|
CCH_RELEASE_TAIL(tdbb, window);
|
||||||
window->win_flags &= ~WIN_garbage_collect;
|
window->win_flags &= ~WIN_garbage_collect;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
CCH_RELEASE(tdbb, window);
|
CCH_RELEASE(tdbb, window);
|
||||||
}
|
|
||||||
|
|
||||||
if (sweeper)
|
if (sweeper)
|
||||||
{
|
{
|
||||||
@ -1739,9 +1663,8 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
rpb->rpb_number = saveRecNo;
|
rpb->rpb_number = saveRecNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onepage) {
|
if (onepage)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(ppage = get_pointer_page(tdbb, rpb->rpb_relation, relPages, window,
|
if (!(ppage = get_pointer_page(tdbb, rpb->rpb_relation, relPages, window,
|
||||||
pp_sequence, LCK_read)))
|
pp_sequence, LCK_read)))
|
||||||
@ -1765,16 +1688,14 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
|
|||||||
slot = 0;
|
slot = 0;
|
||||||
line = 0;
|
line = 0;
|
||||||
|
|
||||||
if (window->win_flags & WIN_large_scan) {
|
if (window->win_flags & WIN_large_scan)
|
||||||
CCH_RELEASE_TAIL(tdbb, window);
|
CCH_RELEASE_TAIL(tdbb, window);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
CCH_RELEASE(tdbb, window);
|
CCH_RELEASE(tdbb, window);
|
||||||
}
|
|
||||||
if (flags & ppg_eof || onepage) {
|
if (flags & ppg_eof || onepage)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1856,21 +1777,19 @@ SLONG DPM_prefetch_bitmap(thread_db* tdbb, jrd_rel* relation, PageBitmap* bitmap
|
|||||||
|
|
||||||
const pointer_page* ppage = get_pointer_page(tdbb, relation, &window, pp_sequence, LCK_read);
|
const pointer_page* ppage = get_pointer_page(tdbb, relation, &window, pp_sequence, LCK_read);
|
||||||
if (!ppage)
|
if (!ppage)
|
||||||
{
|
BUGCHECK(249); // msg 249 pointer page vanished from DPM_prefetch_bitmap
|
||||||
BUGCHECK(249);
|
|
||||||
// msg 249 pointer page vanished from DPM_prefetch_bitmap
|
|
||||||
}
|
|
||||||
pages[i] = slot < ppage->ppg_count ? ppage->ppg_page[slot] : 0;
|
pages[i] = slot < ppage->ppg_count ? ppage->ppg_page[slot] : 0;
|
||||||
CCH_RELEASE(tdbb, &window);
|
CCH_RELEASE(tdbb, &window);
|
||||||
|
|
||||||
if (i++ < dbb->dbb_prefetch_sequence) {
|
if (i++ < dbb->dbb_prefetch_sequence)
|
||||||
prefetch_number = number;
|
prefetch_number = number;
|
||||||
}
|
|
||||||
number = ((dp_sequence + 1) * dbb->dbb_max_records) - 1;
|
number = ((dp_sequence + 1) * dbb->dbb_max_records) - 1;
|
||||||
if (!SBM_next(bitmap, &number, RSE_get_forward)) {
|
|
||||||
|
if (!SBM_next(bitmap, &number, RSE_get_forward))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CCH_PREFETCH(tdbb, pages, i);
|
CCH_PREFETCH(tdbb, pages, i);
|
||||||
return prefetch_number;
|
return prefetch_number;
|
||||||
@ -2002,9 +1921,8 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd:
|
|||||||
}
|
}
|
||||||
|
|
||||||
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
||||||
if (fill < 0) {
|
if (fill < 0)
|
||||||
fill = 0;
|
fill = 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Accomodate max record size i.e. 64K
|
// Accomodate max record size i.e. 64K
|
||||||
const SLONG length = RHD_SIZE + size + fill;
|
const SLONG length = RHD_SIZE + size + fill;
|
||||||
@ -2028,9 +1946,8 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd:
|
|||||||
rpb->rpb_b_line);
|
rpb->rpb_b_line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fill) {
|
if (fill)
|
||||||
memset(header->rhd_data + size, 0, fill);
|
memset(header->rhd_data + size, 0, fill);
|
||||||
}
|
|
||||||
|
|
||||||
Ods::pag* page = rpb->getWindow(tdbb).win_buffer;
|
Ods::pag* page = rpb->getWindow(tdbb).win_buffer;
|
||||||
if (page->pag_flags & dpg_swept)
|
if (page->pag_flags & dpg_swept)
|
||||||
@ -2085,13 +2002,11 @@ RecordNumber DPM_store_blob(thread_db* tdbb, blb* blob, Record* record)
|
|||||||
stack, record, DPM_other);
|
stack, record, DPM_other);
|
||||||
header->blh_flags = rhd_blob;
|
header->blh_flags = rhd_blob;
|
||||||
|
|
||||||
if (blob->blb_flags & BLB_stream) {
|
if (blob->blb_flags & BLB_stream)
|
||||||
header->blh_flags |= rhd_stream_blob;
|
header->blh_flags |= rhd_stream_blob;
|
||||||
}
|
|
||||||
|
|
||||||
if (blob->getLevel()) {
|
if (blob->getLevel())
|
||||||
header->blh_flags |= rhd_large;
|
header->blh_flags |= rhd_large;
|
||||||
}
|
|
||||||
|
|
||||||
blob->toPageHeader(header);
|
blob->toPageHeader(header);
|
||||||
|
|
||||||
@ -2199,10 +2114,8 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
|
|||||||
if (stack)
|
if (stack)
|
||||||
{
|
{
|
||||||
while (stack->hasData())
|
while (stack->hasData())
|
||||||
{
|
|
||||||
CCH_precedence(tdbb, &rpb->getWindow(tdbb), stack->pop());
|
CCH_precedence(tdbb, &rpb->getWindow(tdbb), stack->pop());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CCH_tra_precedence(tdbb, &rpb->getWindow(tdbb), rpb->rpb_transaction_nr);
|
CCH_tra_precedence(tdbb, &rpb->getWindow(tdbb), rpb->rpb_transaction_nr);
|
||||||
CCH_MARK(tdbb, &rpb->getWindow(tdbb));
|
CCH_MARK(tdbb, &rpb->getWindow(tdbb));
|
||||||
@ -2214,19 +2127,18 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
|
|||||||
// a fragmented record header. Compute the amount of fill required.
|
// a fragmented record header. Compute the amount of fill required.
|
||||||
|
|
||||||
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
SLONG fill = (RHDF_SIZE - RHD_SIZE) - size;
|
||||||
if (fill < 0) {
|
if (fill < 0)
|
||||||
fill = 0;
|
fill = 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Accomodate max record size i.e. 64K
|
// Accomodate max record size i.e. 64K
|
||||||
const SLONG length = ROUNDUP(RHD_SIZE + size + fill, ODS_ALIGNMENT);
|
const SLONG length = ROUNDUP(RHD_SIZE + size + fill, ODS_ALIGNMENT);
|
||||||
const USHORT slot = rpb->rpb_line;
|
const USHORT slot = rpb->rpb_line;
|
||||||
|
|
||||||
// Find space on page
|
// Find space on page
|
||||||
SSHORT space = dbb->dbb_page_size;
|
USHORT space = dbb->dbb_page_size;
|
||||||
const SSHORT top = HIGH_WATER(page->dpg_count);
|
const USHORT top = HIGH_WATER(page->dpg_count);
|
||||||
SSHORT available = dbb->dbb_page_size - top;
|
SSHORT available = dbb->dbb_page_size - top;
|
||||||
const SSHORT old_length = page->dpg_rpt[slot].dpg_length;
|
const USHORT old_length = page->dpg_rpt[slot].dpg_length;
|
||||||
page->dpg_rpt[slot].dpg_length = 0;
|
page->dpg_rpt[slot].dpg_length = 0;
|
||||||
|
|
||||||
const data_page::dpg_repeat* index = page->dpg_rpt;
|
const data_page::dpg_repeat* index = page->dpg_rpt;
|
||||||
@ -2245,10 +2157,12 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (length > space - top)
|
||||||
|
space = compress(tdbb, page);
|
||||||
|
|
||||||
|
fb_assert(space >= length);
|
||||||
space -= length;
|
space -= length;
|
||||||
if (space < top) {
|
fb_assert(space >= top);
|
||||||
space = DPM_compress(tdbb, page) - length;
|
|
||||||
}
|
|
||||||
|
|
||||||
page->dpg_rpt[slot].dpg_offset = space;
|
page->dpg_rpt[slot].dpg_offset = space;
|
||||||
page->dpg_rpt[slot].dpg_length = RHD_SIZE + size + fill;
|
page->dpg_rpt[slot].dpg_length = RHD_SIZE + size + fill;
|
||||||
@ -2272,9 +2186,8 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
|
|||||||
rpb->rpb_b_page, rpb->rpb_b_line);
|
rpb->rpb_b_page, rpb->rpb_b_line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fill) {
|
if (fill)
|
||||||
memset(header->rhd_data + size, 0, fill);
|
memset(header->rhd_data + size, 0, fill);
|
||||||
}
|
|
||||||
|
|
||||||
if (page->dpg_header.pag_flags & dpg_swept)
|
if (page->dpg_header.pag_flags & dpg_swept)
|
||||||
{
|
{
|
||||||
@ -2349,6 +2262,60 @@ static void check_swept(thread_db* tdbb, record_param* rpb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static USHORT compress(thread_db* tdbb, data_page* page)
|
||||||
|
{
|
||||||
|
/**************************************
|
||||||
|
*
|
||||||
|
* c o m p r e s s
|
||||||
|
*
|
||||||
|
**************************************
|
||||||
|
*
|
||||||
|
* Functional description
|
||||||
|
* Compress a data page. Return the high water mark.
|
||||||
|
*
|
||||||
|
**************************************/
|
||||||
|
SET_TDBB(tdbb);
|
||||||
|
Database* dbb = tdbb->getDatabase();
|
||||||
|
|
||||||
|
#ifdef VIO_DEBUG
|
||||||
|
VIO_trace(DEBUG_TRACE_ALL,
|
||||||
|
"compress (page)\n");
|
||||||
|
|
||||||
|
VIO_trace(DEBUG_TRACE_ALL_INFO,
|
||||||
|
" sequence %"SLONGFORMAT"\n", page->dpg_sequence);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UCHAR temp_page[MAX_PAGE_SIZE];
|
||||||
|
if (dbb->dbb_page_size > sizeof(temp_page))
|
||||||
|
BUGCHECK(250); // msg 250 temporary page buffer too small
|
||||||
|
|
||||||
|
USHORT space = dbb->dbb_page_size;
|
||||||
|
const data_page::dpg_repeat* const end = page->dpg_rpt + page->dpg_count;
|
||||||
|
|
||||||
|
for (data_page::dpg_repeat* index = page->dpg_rpt; index < end; index++)
|
||||||
|
{
|
||||||
|
if (index->dpg_offset)
|
||||||
|
{
|
||||||
|
// 11-Aug-2004. Nickolay Samofatov.
|
||||||
|
// Copy block of pre-aligned length to avoid putting rubbish from stack into database
|
||||||
|
// This should also work just a little bit faster too.
|
||||||
|
const USHORT l = ROUNDUP(index->dpg_length, ODS_ALIGNMENT);
|
||||||
|
space -= l;
|
||||||
|
memcpy(temp_page + space, (UCHAR *) page + index->dpg_offset, l);
|
||||||
|
index->dpg_offset = space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((UCHAR *) page + space, temp_page + space, dbb->dbb_page_size - space);
|
||||||
|
|
||||||
|
if (page->dpg_header.pag_type != pag_data) {
|
||||||
|
BUGCHECK(251); // msg 251 damaged data page
|
||||||
|
}
|
||||||
|
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space, USHORT length)
|
static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space, USHORT length)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -2392,12 +2359,13 @@ static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space,
|
|||||||
header = (rhdf*) ((UCHAR *) dpage + dpage->dpg_rpt[0].dpg_offset);
|
header = (rhdf*) ((UCHAR *) dpage + dpage->dpg_rpt[0].dpg_offset);
|
||||||
const USHORT flags = header->rhdf_flags;
|
const USHORT flags = header->rhdf_flags;
|
||||||
page_number = header->rhdf_f_page;
|
page_number = header->rhdf_f_page;
|
||||||
|
|
||||||
CCH_RELEASE_TAIL(tdbb, &window);
|
CCH_RELEASE_TAIL(tdbb, &window);
|
||||||
PAG_release_page(tdbb, window.win_page, ZERO_PAGE_NUMBER);
|
PAG_release_page(tdbb, window.win_page, ZERO_PAGE_NUMBER);
|
||||||
if (!(flags & rhd_incomplete)) {
|
|
||||||
|
if (!(flags & rhd_incomplete))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2415,9 +2383,10 @@ static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space,
|
|||||||
blob_page* bpage = (blob_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_blob);
|
blob_page* bpage = (blob_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_blob);
|
||||||
ULONG* page2 = bpage->blp_page;
|
ULONG* page2 = bpage->blp_page;
|
||||||
const ULONG* const end2 = page2 + ((bpage->blp_length - BLP_SIZE) / sizeof(ULONG));
|
const ULONG* const end2 = page2 + ((bpage->blp_length - BLP_SIZE) / sizeof(ULONG));
|
||||||
while (page2 < end2) {
|
|
||||||
|
while (page2 < end2)
|
||||||
PAG_release_page(tdbb, PageNumber(page_space, *page2++), ZERO_PAGE_NUMBER);
|
PAG_release_page(tdbb, PageNumber(page_space, *page2++), ZERO_PAGE_NUMBER);
|
||||||
}
|
|
||||||
CCH_RELEASE_TAIL(tdbb, &window);
|
CCH_RELEASE_TAIL(tdbb, &window);
|
||||||
}
|
}
|
||||||
PAG_release_page(tdbb, PageNumber(page_space, *page1), ZERO_PAGE_NUMBER);
|
PAG_release_page(tdbb, PageNumber(page_space, *page1), ZERO_PAGE_NUMBER);
|
||||||
@ -2537,7 +2506,7 @@ static void fragment(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const SSHORT space = DPM_compress(tdbb, page) - available_space;
|
const USHORT space = compress(tdbb, page) - available_space;
|
||||||
header = (rhdf*) ((SCHAR *) page + space);
|
header = (rhdf*) ((SCHAR *) page + space);
|
||||||
header->rhdf_flags = rhd_deleted;
|
header->rhdf_flags = rhd_deleted;
|
||||||
header->rhdf_f_page = header->rhdf_f_line = 0;
|
header->rhdf_f_page = header->rhdf_f_line = 0;
|
||||||
@ -2686,19 +2655,20 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
|
|||||||
ULONG* slots = ppage->ppg_page;
|
ULONG* slots = ppage->ppg_page;
|
||||||
for (slot = 0; slot < ppage->ppg_count; slot++, slots++)
|
for (slot = 0; slot < ppage->ppg_count; slot++, slots++)
|
||||||
{
|
{
|
||||||
if (*slots == 0) {
|
if (*slots == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (slot < ppage->ppg_count) {
|
if (slot < ppage->ppg_count)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if ((pp_sequence && ppage->ppg_count < dbb->dbb_dp_per_pp) ||
|
if ((pp_sequence && ppage->ppg_count < dbb->dbb_dp_per_pp) ||
|
||||||
(ppage->ppg_count < dbb->dbb_dp_per_pp - 1))
|
(ppage->ppg_count < dbb->dbb_dp_per_pp - 1))
|
||||||
{
|
{
|
||||||
slot = ppage->ppg_count;
|
slot = ppage->ppg_count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ppage->ppg_header.pag_flags & ppg_eof)
|
if (ppage->ppg_header.pag_flags & ppg_eof)
|
||||||
{
|
{
|
||||||
WIN new_pp_window(relPages->rel_pg_space_id, -1);
|
WIN new_pp_window(relPages->rel_pg_space_id, -1);
|
||||||
@ -2728,6 +2698,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
|
|||||||
ppage->ppg_next = new_pp_window.win_page.getPageNum();
|
ppage->ppg_next = new_pp_window.win_page.getPageNum();
|
||||||
--pp_sequence;
|
--pp_sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCH_RELEASE(tdbb, &pp_window);
|
CCH_RELEASE(tdbb, &pp_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2784,9 +2755,8 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
|
|||||||
UCHAR* bits = (UCHAR*) (ppage->ppg_page + dbb->dbb_dp_per_pp);
|
UCHAR* bits = (UCHAR*) (ppage->ppg_page + dbb->dbb_dp_per_pp);
|
||||||
PPG_DP_BIT_CLEAR(bits, slot, PPG_DP_ALL_BITS);
|
PPG_DP_BIT_CLEAR(bits, slot, PPG_DP_ALL_BITS);
|
||||||
|
|
||||||
if (type != DPM_primary) {
|
if (type != DPM_primary)
|
||||||
PPG_DP_BIT_SET(bits, slot, ppg_dp_secondary);
|
PPG_DP_BIT_SET(bits, slot, ppg_dp_secondary);
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < cntAlloc; i++)
|
for (int i = 1; i < cntAlloc; i++)
|
||||||
{
|
{
|
||||||
@ -2854,9 +2824,9 @@ static UCHAR* find_space(thread_db* tdbb,
|
|||||||
// Scan allocated lines looking for an empty slot, the high water mark,
|
// Scan allocated lines looking for an empty slot, the high water mark,
|
||||||
// and the amount of space potentially available on the page
|
// and the amount of space potentially available on the page
|
||||||
|
|
||||||
SSHORT space = dbb->dbb_page_size;
|
USHORT space = dbb->dbb_page_size;
|
||||||
USHORT slot = 0;
|
USHORT slot = 0;
|
||||||
SSHORT used = HIGH_WATER(page->dpg_count);
|
USHORT used = HIGH_WATER(page->dpg_count);
|
||||||
|
|
||||||
{ // scope
|
{ // scope
|
||||||
const bool reserving = !(dbb->dbb_flags & DBB_no_reserve);
|
const bool reserving = !(dbb->dbb_flags & DBB_no_reserve);
|
||||||
@ -2877,15 +2847,13 @@ static UCHAR* find_space(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!slot) {
|
else if (!slot)
|
||||||
slot = i;
|
slot = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // scope
|
} // scope
|
||||||
|
|
||||||
if (!slot) {
|
if (!slot)
|
||||||
used += sizeof(data_page::dpg_repeat);
|
used += sizeof(data_page::dpg_repeat);
|
||||||
}
|
|
||||||
|
|
||||||
// If there isn't space, give up
|
// If there isn't space, give up
|
||||||
|
|
||||||
@ -2898,32 +2866,32 @@ static UCHAR* find_space(thread_db* tdbb,
|
|||||||
mark_full(tdbb, rpb);
|
mark_full(tdbb, rpb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
|
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's space on page. If the line index needs expansion, do so.
|
// There's space on page. If the line index needs expansion, do so.
|
||||||
// If the page need to be compressed, compress it.
|
// If the page need to be compressed, compress it.
|
||||||
|
|
||||||
while (stack.hasData()) {
|
while (stack.hasData())
|
||||||
CCH_precedence(tdbb, &rpb->getWindow(tdbb), stack.pop());
|
CCH_precedence(tdbb, &rpb->getWindow(tdbb), stack.pop());
|
||||||
}
|
|
||||||
CCH_MARK(tdbb, &rpb->getWindow(tdbb));
|
CCH_MARK(tdbb, &rpb->getWindow(tdbb));
|
||||||
|
|
||||||
{ // scope
|
{ // scope
|
||||||
const USHORT rec_segments = page->dpg_count + (slot ? 0 : 1);
|
const USHORT rec_segments = page->dpg_count + (slot ? 0 : 1);
|
||||||
fb_assert(rec_segments); // zero is a disaster in macro HIGH_WATER
|
fb_assert(rec_segments); // zero is a disaster in macro HIGH_WATER
|
||||||
if (aligned_size > space - HIGH_WATER(rec_segments))
|
if (aligned_size > space - HIGH_WATER(rec_segments))
|
||||||
space = DPM_compress(tdbb, page);
|
space = compress(tdbb, page);
|
||||||
} // scope
|
} // scope
|
||||||
|
|
||||||
if (!slot) {
|
if (!slot)
|
||||||
slot = page->dpg_count++;
|
slot = page->dpg_count++;
|
||||||
}
|
|
||||||
|
|
||||||
|
fb_assert(space >= aligned_size);
|
||||||
space -= aligned_size;
|
space -= aligned_size;
|
||||||
|
|
||||||
data_page::dpg_repeat* index = &page->dpg_rpt[slot];
|
data_page::dpg_repeat* index = &page->dpg_rpt[slot];
|
||||||
index->dpg_length = size;
|
index->dpg_length = size;
|
||||||
index->dpg_offset = space;
|
index->dpg_offset = space;
|
||||||
@ -2931,9 +2899,8 @@ static UCHAR* find_space(thread_db* tdbb,
|
|||||||
rpb->rpb_line = slot;
|
rpb->rpb_line = slot;
|
||||||
rpb->rpb_number.setValue(((SINT64) page->dpg_sequence) * dbb->dbb_max_records + slot);
|
rpb->rpb_number.setValue(((SINT64) page->dpg_sequence) * dbb->dbb_max_records + slot);
|
||||||
|
|
||||||
if (record) {
|
if (record)
|
||||||
record->pushPrecedence(PageNumber(DB_PAGE_SPACE, rpb->rpb_page));
|
record->pushPrecedence(PageNumber(DB_PAGE_SPACE, rpb->rpb_page));
|
||||||
}
|
|
||||||
|
|
||||||
if (page->dpg_count == 1)
|
if (page->dpg_count == 1)
|
||||||
{
|
{
|
||||||
@ -2961,14 +2928,12 @@ static bool get_header(WIN* window, USHORT line, record_param* rpb)
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
const data_page* page = (data_page*) window->win_buffer;
|
const data_page* page = (data_page*) window->win_buffer;
|
||||||
if (line >= page->dpg_count) {
|
if (line >= page->dpg_count)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
const data_page::dpg_repeat* index = &page->dpg_rpt[line];
|
const data_page::dpg_repeat* index = &page->dpg_rpt[line];
|
||||||
if (index->dpg_offset == 0) {
|
if (index->dpg_offset == 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
rhdf* header = (rhdf*) ((SCHAR *) page + index->dpg_offset);
|
rhdf* header = (rhdf*) ((SCHAR *) page + index->dpg_offset);
|
||||||
rpb->rpb_page = window->win_page.getPageNum();
|
rpb->rpb_page = window->win_page.getPageNum();
|
||||||
@ -3026,12 +2991,12 @@ static pointer_page* get_pointer_page(thread_db* tdbb,
|
|||||||
{
|
{
|
||||||
DPM_scan_pages(tdbb);
|
DPM_scan_pages(tdbb);
|
||||||
// If the relation is gone, then we can't do anything anymore.
|
// If the relation is gone, then we can't do anything anymore.
|
||||||
if (!relation || !(vector = relPages->rel_pages)) {
|
if (!relation || !(vector = relPages->rel_pages))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if (sequence < vector->count()) {
|
if (sequence < vector->count())
|
||||||
break; // we are in business again
|
break; // we are in business again
|
||||||
}
|
|
||||||
window->win_page = (*vector)[vector->count() - 1];
|
window->win_page = (*vector)[vector->count() - 1];
|
||||||
const pointer_page* page = (pointer_page*) CCH_FETCH(tdbb, window, lock, pag_pointer);
|
const pointer_page* page = (pointer_page*) CCH_FETCH(tdbb, window, lock, pag_pointer);
|
||||||
const ULONG next_ppg = page->ppg_next;
|
const ULONG next_ppg = page->ppg_next;
|
||||||
@ -3049,9 +3014,7 @@ static pointer_page* get_pointer_page(thread_db* tdbb,
|
|||||||
pointer_page* page = (pointer_page*) CCH_FETCH(tdbb, window, lock, pag_pointer);
|
pointer_page* page = (pointer_page*) CCH_FETCH(tdbb, window, lock, pag_pointer);
|
||||||
|
|
||||||
if (page->ppg_relation != relation->rel_id || page->ppg_sequence != sequence)
|
if (page->ppg_relation != relation->rel_id || page->ppg_sequence != sequence)
|
||||||
{
|
|
||||||
CORRUPT(259); // msg 259 bad pointer page
|
CORRUPT(259); // msg 259 bad pointer page
|
||||||
}
|
|
||||||
|
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
@ -3094,6 +3057,7 @@ static rhd* locate_space(thread_db* tdbb,
|
|||||||
|
|
||||||
const pointer_page* ppage =
|
const pointer_page* ppage =
|
||||||
get_pointer_page(tdbb, relation, relPages, window, pp_sequence, LCK_read);
|
get_pointer_page(tdbb, relation, relPages, window, pp_sequence, LCK_read);
|
||||||
|
|
||||||
if (ppage)
|
if (ppage)
|
||||||
{
|
{
|
||||||
if (slot < ppage->ppg_count && ((dp_primary = ppage->ppg_page[slot])) )
|
if (slot < ppage->ppg_count && ((dp_primary = ppage->ppg_page[slot])) )
|
||||||
@ -3103,15 +3067,13 @@ static rhd* locate_space(thread_db* tdbb,
|
|||||||
if (space)
|
if (space)
|
||||||
return (rhd*) space;
|
return (rhd*) space;
|
||||||
|
|
||||||
if (!window->win_page.isTemporary()) {
|
if (!window->win_page.isTemporary())
|
||||||
CCH_get_related(tdbb, window->win_page, lowPages);
|
CCH_get_related(tdbb, window->win_page, lowPages);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
CCH_RELEASE(tdbb, window);
|
CCH_RELEASE(tdbb, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Look for space anywhere
|
// Look for space anywhere
|
||||||
|
|
||||||
@ -3135,10 +3097,8 @@ static rhd* locate_space(thread_db* tdbb,
|
|||||||
const pointer_page* ppage =
|
const pointer_page* ppage =
|
||||||
get_pointer_page(tdbb, relation, relPages, window, pp_sequence, ppLock);
|
get_pointer_page(tdbb, relation, relPages, window, pp_sequence, ppLock);
|
||||||
if (!ppage)
|
if (!ppage)
|
||||||
{
|
BUGCHECK(254); // msg 254 pointer page vanished from relation list in locate_space
|
||||||
BUGCHECK(254);
|
|
||||||
// msg 254 pointer page vanished from relation list in locate_space
|
|
||||||
}
|
|
||||||
const ULONG pp_number = window->win_page.getPageNum();
|
const ULONG pp_number = window->win_page.getPageNum();
|
||||||
for (USHORT slot = ppage->ppg_min_space; slot < ppage->ppg_count; slot++)
|
for (USHORT slot = ppage->ppg_min_space; slot < ppage->ppg_count; slot++)
|
||||||
{
|
{
|
||||||
@ -3223,12 +3183,13 @@ static rhd* locate_space(thread_db* tdbb,
|
|||||||
BUGCHECK(254);
|
BUGCHECK(254);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const UCHAR flags = ppage->ppg_header.pag_flags;
|
const UCHAR flags = ppage->ppg_header.pag_flags;
|
||||||
CCH_RELEASE(tdbb, window);
|
CCH_RELEASE(tdbb, window);
|
||||||
if (flags & ppg_eof) {
|
|
||||||
|
if (flags & ppg_eof)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Sigh. No space. Extend relation. Try for a while in case someone grabs the page
|
// Sigh. No space. Extend relation. Try for a while in case someone grabs the page
|
||||||
// before we can get it locked, then give up on the assumption that things
|
// before we can get it locked, then give up on the assumption that things
|
||||||
@ -3239,17 +3200,16 @@ static rhd* locate_space(thread_db* tdbb,
|
|||||||
{
|
{
|
||||||
extend_relation(tdbb, relation, window, type);
|
extend_relation(tdbb, relation, window, type);
|
||||||
space = find_space(tdbb, rpb, size, stack, record, type);
|
space = find_space(tdbb, rpb, size, stack, record, type);
|
||||||
if (space) {
|
|
||||||
|
if (space)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (i == 20) {
|
|
||||||
BUGCHECK(255); // msg 255 cannot find free space
|
|
||||||
}
|
|
||||||
|
|
||||||
if (record) {
|
if (i == 20)
|
||||||
|
BUGCHECK(255); // msg 255 cannot find free space
|
||||||
|
|
||||||
|
if (record)
|
||||||
record->pushPrecedence(PageNumber(DB_PAGE_SPACE, window->win_page.getPageNum()));
|
record->pushPrecedence(PageNumber(DB_PAGE_SPACE, window->win_page.getPageNum()));
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef VIO_DEBUG
|
#ifdef VIO_DEBUG
|
||||||
VIO_trace(DEBUG_WRITES_INFO,
|
VIO_trace(DEBUG_WRITES_INFO,
|
||||||
@ -3324,11 +3284,10 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
|
|||||||
dpage = (data_page*) CCH_FETCH_TIMEOUT(tdbb, &rpb->getWindow(tdbb), LCK_read, pag_data, -1);
|
dpage = (data_page*) CCH_FETCH_TIMEOUT(tdbb, &rpb->getWindow(tdbb), LCK_read, pag_data, -1);
|
||||||
|
|
||||||
// In case of a latch timeout, release the latch on the pointer page and retry.
|
// In case of a latch timeout, release the latch on the pointer page and retry.
|
||||||
if (!dpage) {
|
if (!dpage)
|
||||||
CCH_RELEASE(tdbb, &pp_window);
|
CCH_RELEASE(tdbb, &pp_window);
|
||||||
}
|
|
||||||
} while (!dpage);
|
|
||||||
|
|
||||||
|
} while (!dpage);
|
||||||
|
|
||||||
const UCHAR flags = dpage->dpg_header.pag_flags;
|
const UCHAR flags = dpage->dpg_header.pag_flags;
|
||||||
const bool dpEmpty = (dpage->dpg_count == 0);
|
const bool dpEmpty = (dpage->dpg_count == 0);
|
||||||
@ -3386,28 +3345,22 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bit = PPG_DP_BIT_MASK(slot, ppg_dp_large);
|
bit = PPG_DP_BIT_MASK(slot, ppg_dp_large);
|
||||||
if (flags & dpg_large) {
|
if (flags & dpg_large)
|
||||||
*byte |= bit;
|
*byte |= bit;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
*byte &= ~bit;
|
*byte &= ~bit;
|
||||||
}
|
|
||||||
|
|
||||||
bit = PPG_DP_BIT_MASK(slot, ppg_dp_swept);
|
bit = PPG_DP_BIT_MASK(slot, ppg_dp_swept);
|
||||||
if (flags & dpg_swept) {
|
if (flags & dpg_swept)
|
||||||
*byte |= bit;
|
*byte |= bit;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
*byte &= ~bit;
|
*byte &= ~bit;
|
||||||
}
|
|
||||||
|
|
||||||
bit = PPG_DP_BIT_MASK(slot, ppg_dp_secondary);
|
bit = PPG_DP_BIT_MASK(slot, ppg_dp_secondary);
|
||||||
if (flags & dpg_secondary) {
|
if (flags & dpg_secondary)
|
||||||
*byte |= bit;
|
*byte |= bit;
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
*byte &= ~bit;
|
*byte &= ~bit;
|
||||||
}
|
|
||||||
|
|
||||||
bit = PPG_DP_BIT_MASK(slot, ppg_dp_empty);
|
bit = PPG_DP_BIT_MASK(slot, ppg_dp_empty);
|
||||||
if (dpEmpty)
|
if (dpEmpty)
|
||||||
@ -3417,9 +3370,8 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
|
|||||||
relPages->rel_pri_data_space = MIN(pp_sequence, relPages->rel_pri_data_space);
|
relPages->rel_pri_data_space = MIN(pp_sequence, relPages->rel_pri_data_space);
|
||||||
relPages->rel_sec_data_space = MIN(pp_sequence, relPages->rel_sec_data_space);
|
relPages->rel_sec_data_space = MIN(pp_sequence, relPages->rel_sec_data_space);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
*byte &= ~bit;
|
*byte &= ~bit;
|
||||||
}
|
|
||||||
|
|
||||||
CCH_RELEASE(tdbb, &pp_window);
|
CCH_RELEASE(tdbb, &pp_window);
|
||||||
}
|
}
|
||||||
@ -3513,12 +3465,11 @@ static void store_big_record(thread_db* tdbb,
|
|||||||
*--out = 0;
|
*--out = 0;
|
||||||
++size;
|
++size;
|
||||||
}
|
}
|
||||||
else if (count > 0) {
|
else if (count > 0)
|
||||||
++size;
|
++size;
|
||||||
}
|
|
||||||
if (prior.getPageNum()) {
|
if (prior.getPageNum())
|
||||||
CCH_precedence(tdbb, &rpb->getWindow(tdbb), prior);
|
CCH_precedence(tdbb, &rpb->getWindow(tdbb), prior);
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef VIO_DEBUG
|
#ifdef VIO_DEBUG
|
||||||
VIO_trace(DEBUG_WRITES_INFO,
|
VIO_trace(DEBUG_WRITES_INFO,
|
||||||
@ -3571,7 +3522,6 @@ static void store_big_record(thread_db* tdbb,
|
|||||||
page->dpg_header.pag_flags |= dpg_large;
|
page->dpg_header.pag_flags |= dpg_large;
|
||||||
mark_full(tdbb, rpb);
|
mark_full(tdbb, rpb);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
|
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,6 @@ void DPM_backout(Jrd::thread_db*, Jrd::record_param*);
|
|||||||
void DPM_backout_mark(Jrd::thread_db*, Jrd::record_param*, const Jrd::jrd_tra*);
|
void DPM_backout_mark(Jrd::thread_db*, Jrd::record_param*, const Jrd::jrd_tra*);
|
||||||
double DPM_cardinality(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::Format*);
|
double DPM_cardinality(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::Format*);
|
||||||
bool DPM_chain(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*);
|
bool DPM_chain(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*);
|
||||||
int DPM_compress(Jrd::thread_db*, Ods::data_page*);
|
|
||||||
void DPM_create_relation(Jrd::thread_db*, Jrd::jrd_rel*);
|
void DPM_create_relation(Jrd::thread_db*, Jrd::jrd_rel*);
|
||||||
ULONG DPM_data_pages(Jrd::thread_db*, Jrd::jrd_rel*);
|
ULONG DPM_data_pages(Jrd::thread_db*, Jrd::jrd_rel*);
|
||||||
void DPM_delete(Jrd::thread_db*, Jrd::record_param*, ULONG);
|
void DPM_delete(Jrd::thread_db*, Jrd::record_param*, ULONG);
|
||||||
|
@ -248,7 +248,7 @@ public:
|
|||||||
Firebird::UtilSvc* uSvc;
|
Firebird::UtilSvc* uSvc;
|
||||||
dba_fil* files;
|
dba_fil* files;
|
||||||
dba_rel* relations;
|
dba_rel* relations;
|
||||||
SSHORT page_size;
|
USHORT page_size;
|
||||||
USHORT dp_per_pp;
|
USHORT dp_per_pp;
|
||||||
USHORT max_records;
|
USHORT max_records;
|
||||||
SLONG page_number;
|
SLONG page_number;
|
||||||
@ -584,7 +584,7 @@ int gstat(Firebird::UtilSvc* uSvc)
|
|||||||
|
|
||||||
dba_fil* current = db_open(fileName.c_str(), fileName.length());
|
dba_fil* current = db_open(fileName.c_str(), fileName.length());
|
||||||
|
|
||||||
SCHAR temp[1024];
|
SCHAR temp[RAW_HEADER_SIZE];
|
||||||
tddba->page_size = sizeof(temp);
|
tddba->page_size = sizeof(temp);
|
||||||
tddba->global_buffer = (pag*) temp;
|
tddba->global_buffer = (pag*) temp;
|
||||||
tddba->page_number = -1;
|
tddba->page_number = -1;
|
||||||
@ -2024,10 +2024,10 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
|
|||||||
db_error(errno);
|
db_error(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
SSHORT length = tddba->page_size;
|
USHORT length = tddba->page_size;
|
||||||
for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;)
|
for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;)
|
||||||
{
|
{
|
||||||
const SSHORT l = read(fil->fil_desc, p, length);
|
const USHORT l = read(fil->fil_desc, p, length);
|
||||||
if (l < 0)
|
if (l < 0)
|
||||||
{
|
{
|
||||||
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());
|
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());
|
||||||
|
Loading…
Reference in New Issue
Block a user