8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 22:03:03 +01:00

Replace fixed size array of shared latches (bdb_shared) by queue. It allows to have more than 20 simultaneous readers for hot pages and eliminate needs for scanning full array when searching for current thread's latch

This commit is contained in:
hvlad 2008-06-05 08:35:18 +00:00
parent b021758834
commit 6bff6c6649
3 changed files with 100 additions and 33 deletions

View File

@ -201,6 +201,63 @@ const SLONG MIN_BUFFER_SEGMENT = 65536;
#define BLOCK(fld_ptr, type, fld) (type)((SCHAR*) fld_ptr - OFFSET (type, fld))
static inline SharedLatch* allocSharedLatch(thread_db* tdbb, BufferDesc* bdb)
{
BufferControl* bcb = bdb->bdb_dbb->dbb_bcb;
SharedLatch* latch;
if (QUE_NOT_EMPTY(bcb->bcb_free_slt))
{
QUE que_inst = bcb->bcb_free_slt.que_forward;
QUE_DELETE(*que_inst);
latch = BLOCK(que_inst, SharedLatch*, slt_bdb_que);
}
else
{
const int BATCH_ALLOC = 64;
Database* dbb = bdb->bdb_dbb;
SharedLatch *latches = latch = FB_NEW(*dbb->dbb_bufferpool) SharedLatch[BATCH_ALLOC];
for (int i = 1; i < BATCH_ALLOC; i++) {
QUE_APPEND(bcb->bcb_free_slt, latches[i].slt_bdb_que);
}
}
latch->slt_bdb = bdb;
QUE_APPEND(bdb->bdb_shared, latch->slt_bdb_que);
latch->slt_tdbb = tdbb;
QUE_APPEND(tdbb->tdbb_latches, latch->slt_tdbb_que);
return latch;
}
static inline void freeSharedLatch(thread_db* tdbb, BufferControl* bcb, SharedLatch* latch)
{
latch->slt_bdb = NULL;
QUE_DELETE(latch->slt_bdb_que);
QUE_INSERT(bcb->bcb_free_slt, latch->slt_bdb_que);
latch->slt_tdbb = NULL;
QUE_DELETE(latch->slt_tdbb_que);
}
static inline SharedLatch* findSharedLatch(thread_db* tdbb, BufferDesc* bdb)
{
for (QUE que_inst = tdbb->tdbb_latches.que_forward; que_inst != &tdbb->tdbb_latches;
que_inst = que_inst->que_forward)
{
SharedLatch *latch = BLOCK(que_inst, SharedLatch*, slt_tdbb_que);
fb_assert(latch->slt_tdbb == tdbb);
if (latch->slt_bdb == bdb) {
return latch;
}
}
return NULL;
}
//
//#define BCB_MUTEX_ACQUIRE
//#define BCB_MUTEX_RELEASE
@ -1672,6 +1729,7 @@ void CCH_init(thread_db* tdbb, ULONG number)
#endif
QUE_INIT(bcb->bcb_empty);
QUE_INIT(bcb->bcb_free_lwt);
QUE_INIT(bcb->bcb_free_slt);
// initialization of memory is system-specific
@ -2358,10 +2416,14 @@ void CCH_unwind(thread_db* tdbb, const bool punt)
bdb->bdb_flags &= ~(BDB_writer | BDB_faked | BDB_must_write);
release_bdb(tdbb, bdb, true, false, false);
}
for (int i = 0; i < BDB_max_shared; ++i) {
if (bdb->bdb_shared[i] == tdbb) {
release_bdb(tdbb, bdb, true, false, false);
}
// hvlad : as far as i understand thread can't hold more than two shared lathes
// on the same bdb, so findSharedLatch below will not be called many times
SharedLatch *latch = findSharedLatch(tdbb, bdb);
while (latch)
{
release_bdb(tdbb, bdb, true, false, false);
latch = findSharedLatch(tdbb, bdb);
}
#ifndef SUPERSERVER
const pag* const page = bdb->bdb_buffer;
@ -2587,6 +2649,7 @@ static BufferDesc* alloc_bdb(thread_db* tdbb, BufferControl* bcb, UCHAR** memory
QUE_INIT(bdb->bdb_higher);
QUE_INIT(bdb->bdb_lower);
QUE_INIT(bdb->bdb_waiters);
QUE_INIT(bdb->bdb_shared);
QUE_INSERT(bcb->bcb_empty, bdb->bdb_que);
#ifdef DIRTY_LIST
QUE_INIT(bdb->bdb_dirty);
@ -4667,6 +4730,8 @@ static void expand_buffers(thread_db* tdbb, ULONG number)
QUE_DELETE(old->bcb_empty);
QUE_INSERT(old->bcb_free_lwt, new_block->bcb_free_lwt);
QUE_DELETE(old->bcb_free_lwt);
QUE_INSERT(old->bcb_free_slt, new_block->bcb_free_slt);
QUE_DELETE(old->bcb_free_slt);
/* Copy addresses of previously allocated buffer space to new block */
@ -5113,7 +5178,7 @@ static SSHORT latch_bdb(
switch (type) {
case LATCH_shared:
++bdb->bdb_use_count;
bdb->bdb_shared[0] = tdbb;
allocSharedLatch(tdbb, bdb);
break;
case LATCH_exclusive:
++bdb->bdb_use_count;
@ -5146,8 +5211,6 @@ static SSHORT latch_bdb(
flag is set, then an exclusive latch request will be followed by
an io latch request. */
SSHORT i;
switch (type) {
case LATCH_none:
@ -5167,9 +5230,7 @@ static SSHORT latch_bdb(
/* Note that Firebird often 'hands-off' to the same page, for both
shared and exlusive latches. */
/* Check if we own already an exclusive latch. */
for (i = 0; (i < BDB_max_shared) && (bdb->bdb_shared[i] != tdbb);
i++);
if (i >= BDB_max_shared) { /* we don't own a shared latch yet */
if (!findSharedLatch(tdbb, bdb)) { /* we don't own a shared latch yet */
/* If there are latch-waiters, and they are not waiting for an
io_latch, then we have to wait also (there must be a exclusive
latch waiter). If there is an IO in progress, the violate the
@ -5183,12 +5244,8 @@ static SSHORT latch_bdb(
/* Nobody owns an exlusive latch, or sneak ahead of exclusive latch
waiters while an io is in progress. */
for (i = 0; (i < BDB_max_shared) && bdb->bdb_shared[i]; i++); // empty loop body
if (i >= BDB_max_shared) {
break;
}
++bdb->bdb_use_count;
bdb->bdb_shared[i] = tdbb;
allocSharedLatch(tdbb, bdb);
// LATCH_MUTEX_RELEASE;
return 0;
@ -5860,7 +5917,6 @@ static void release_bdb(thread_db* tdbb,
* If rel_mark_latch is true, the value of downgrade_latch is ignored.
*
**************************************/
SSHORT i;
// LATCH_MUTEX_ACQUIRE;
@ -5884,8 +5940,7 @@ static void release_bdb(thread_db* tdbb,
}
if (bdb->bdb_exclusive == tdbb) {
bdb->bdb_exclusive = 0;
for (i = 0; bdb->bdb_shared[i]; i++); // empty loop body
bdb->bdb_shared[i] = tdbb;
allocSharedLatch(tdbb, bdb);
}
else {
// LATCH_MUTEX_RELEASE;
@ -5899,7 +5954,11 @@ static void release_bdb(thread_db* tdbb,
--bdb->bdb_use_count;
if (!bdb->bdb_use_count) { /* All latches are released */
bdb->bdb_exclusive = bdb->bdb_io = 0;
for (i = 0; i < BDB_max_shared; bdb->bdb_shared[i++] = 0); // null loop body
while (QUE_NOT_EMPTY(bdb->bdb_shared))
{
SharedLatch* latch = BLOCK(bdb->bdb_shared.que_forward, SharedLatch*, slt_bdb_que);
freeSharedLatch(tdbb, bdb->bdb_dbb->dbb_bcb, latch);
}
}
else if (bdb->bdb_io) { /* This is a release for an io or an exclusive latch */
if (bdb->bdb_io == tdbb) { /* We have an io latch */
@ -5918,10 +5977,9 @@ static void release_bdb(thread_db* tdbb,
}
}
else { /* This is a release for a shared latch */
for (i = 0; (i < BDB_max_shared) && (bdb->bdb_shared[i] != tdbb);
i++); // null loop body
if (i < BDB_max_shared) {
bdb->bdb_shared[i] = 0;
SharedLatch* latch = findSharedLatch(tdbb, bdb);
if (latch) {
freeSharedLatch(tdbb, bdb->bdb_dbb->dbb_bcb, latch);
}
}
}
@ -5936,12 +5994,11 @@ static void release_bdb(thread_db* tdbb,
bdb->bdb_io = 0;
}
else {
for (i = 0; (i < BDB_max_shared) && (bdb->bdb_shared[i] != tdbb);
i++); // null loop body
if (i >= BDB_max_shared) {
SharedLatch* latch = findSharedLatch(tdbb, bdb);
if (!latch) {
cache_bugcheck(300); /* can't find shared latch */
}
bdb->bdb_shared[i] = 0;
freeSharedLatch(tdbb, bdb->bdb_dbb->dbb_bcb, latch);
}
}
@ -5998,12 +6055,8 @@ static void release_bdb(thread_db* tdbb,
LATCH_MUTEX_RELEASE;
return; */
}
for (i = 0; (i < BDB_max_shared) && bdb->bdb_shared[i]; i++);
if (i >= BDB_max_shared) {
break;
}
++bdb->bdb_use_count;
bdb->bdb_shared[i] = lwt->lwt_tdbb;
SharedLatch* latch = allocSharedLatch(lwt->lwt_tdbb, bdb);
lwt->lwt_flags &= ~LWT_pending;
ISC_event_post(&lwt->lwt_event);
granted = true;

View File

@ -104,6 +104,7 @@ public:
#endif
Precedence* bcb_free; /* Free precedence blocks */
que bcb_free_lwt; /* Free latch wait blocks */
que bcb_free_slt; // Free shared latch blocks
SSHORT bcb_flags; /* see below */
SSHORT bcb_free_minimum; /* Threshold to activate cache writer */
ULONG bcb_count; /* Number of buffers allocated */
@ -167,7 +168,7 @@ public:
ULONG bdb_difference_page; // Number of page in difference file, NBAK
SLONG bdb_backup_lock_owner; // Logical owner of database_lock for buffer
ULONG bdb_writeable_mark; // mark value used in precedence graph walk
thread_db* bdb_shared[BDB_max_shared]; /* threads holding shared latches */
que bdb_shared; // shared latches queue
};
/* bdb_flags */
@ -258,6 +259,16 @@ public:
const int LWT_pending = 1; /* latch request is pending */
// Shared Latch
class SharedLatch
{
public:
thread_db* slt_tdbb; // thread holding latch
BufferDesc* slt_bdb; // buffer for which is this latch
que slt_tdbb_que; // thread's latches queue
que slt_bdb_que; // buffer's latches queue
};
#include "../jrd/os/pio.h"
/* Constants used by prefetch mechanism */

View File

@ -632,6 +632,7 @@ public:
tdbb_quantum = QUANTUM;
tdbb_flags = 0;
tdbb_temp_attid = tdbb_temp_traid = 0;
QUE_INIT(tdbb_latches);
reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy();
tdbb_status_vector = status;
@ -645,6 +646,8 @@ public:
SLONG tdbb_temp_attid; // current temporary table scope
SLONG tdbb_temp_traid; // current temporary table scope
que tdbb_latches; // shared latches hold by thread
MemoryPool* getDefaultPool()
{