- improvement to error handling in pobj: now properly handles resource
allocation errors (at least most cases...?), including hash/queue library calls.
This commit is contained in:
parent
c94bee33a3
commit
eec80a0e38
2 changed files with 288 additions and 151 deletions
266
src/pobj/pobj.c
266
src/pobj/pobj.c
|
@ -90,7 +90,7 @@ struct pobj_repo_list {
|
||||||
struct pobj_repo_list_item *list;
|
struct pobj_repo_list_item *list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pobj_repo_list *g_pobj_repo_list;
|
static struct pobj_repo_list *g_pobj_repo_list = NULL;
|
||||||
static int g_pobj_repo_list_max;
|
static int g_pobj_repo_list_max;
|
||||||
static recordid g_pobj_last_seg_rid;
|
static recordid g_pobj_last_seg_rid;
|
||||||
struct repo_seg g_pobj_last_seg;
|
struct repo_seg g_pobj_last_seg;
|
||||||
|
@ -111,7 +111,7 @@ struct static_repo_list {
|
||||||
struct static_repo_list_item *list;
|
struct static_repo_list_item *list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct static_repo_list *g_static_repo_list;
|
static struct static_repo_list *g_static_repo_list = NULL;
|
||||||
static int g_static_repo_list_max;
|
static int g_static_repo_list_max;
|
||||||
static recordid g_static_last_seg_rid;
|
static recordid g_static_last_seg_rid;
|
||||||
struct repo_seg g_static_last_seg;
|
struct repo_seg g_static_last_seg;
|
||||||
|
@ -1422,36 +1422,6 @@ pobj_static_update_ref (void *static_tmp_ptr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
pobj_restore (void *objid, size_t size, recordid *rid,
|
|
||||||
struct hash *pobj_convert_hash, int xid)
|
|
||||||
{
|
|
||||||
struct pobj *p;
|
|
||||||
void *obj;
|
|
||||||
|
|
||||||
debug_start ();
|
|
||||||
|
|
||||||
debug ("restoring objid=%p size=%d (%d) rid={%d,%d,%ld}",
|
|
||||||
objid, size, POBJ_SIZE (size), rid->page, rid->slot, rid->size);
|
|
||||||
|
|
||||||
/* Allocate memory. */
|
|
||||||
p = (struct pobj *) g_memfunc.malloc (POBJ_SIZE (size));
|
|
||||||
obj = POBJ2OBJ (p);
|
|
||||||
|
|
||||||
debug ("new object allocated at %p (%p)", obj, (void *) p);
|
|
||||||
|
|
||||||
/* Read object from backing store. */
|
|
||||||
Tread (xid, *rid, p);
|
|
||||||
|
|
||||||
debug ("inserting %p->%p conversion pair",
|
|
||||||
objid, obj);
|
|
||||||
|
|
||||||
/* Insert old/new objid pair to conversion table. */
|
|
||||||
hash_insert (pobj_convert_hash, OBJ2KEY (objid), (unsigned long) obj);
|
|
||||||
|
|
||||||
debug_end ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
pobj_adjust (void *old_objid, struct hash *pobj_convert_hash, int xid)
|
pobj_adjust (void *old_objid, struct hash *pobj_convert_hash, int xid)
|
||||||
{
|
{
|
||||||
|
@ -1554,12 +1524,15 @@ pobj_boot_restore (int xid)
|
||||||
{
|
{
|
||||||
struct hash *pobj_convert_hash;
|
struct hash *pobj_convert_hash;
|
||||||
recordid tmp_rid;
|
recordid tmp_rid;
|
||||||
void *new_objid;
|
struct pobj *p;
|
||||||
|
void *objid, *new_objid;
|
||||||
|
size_t size;
|
||||||
int i = 0, j;
|
int i = 0, j;
|
||||||
int changed = 0;
|
|
||||||
int count;
|
int count;
|
||||||
struct pobj_repo_list_item *pobj_slot;
|
struct pobj_repo_list_item *pobj_slot;
|
||||||
struct static_repo_list_item *static_slot;
|
struct static_repo_list_item *static_slot;
|
||||||
|
int adjusted = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
|
||||||
debug_start ();
|
debug_start ();
|
||||||
|
@ -1591,6 +1564,7 @@ pobj_boot_restore (int xid)
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
XFREE (g_pobj_repo_list[i].list);
|
XFREE (g_pobj_repo_list[i].list);
|
||||||
XFREE (g_pobj_repo_list);
|
XFREE (g_pobj_repo_list);
|
||||||
|
g_pobj_repo_list = NULL;
|
||||||
}
|
}
|
||||||
debug_end ();
|
debug_end ();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1622,19 +1596,64 @@ pobj_boot_restore (int xid)
|
||||||
* Reconstruct heap objects.
|
* Reconstruct heap objects.
|
||||||
*/
|
*/
|
||||||
debug ("reconstructing objects and forming conversion table...");
|
debug ("reconstructing objects and forming conversion table...");
|
||||||
pobj_convert_hash = hash_new (CONVERT_HASH_NBUCKEXP);
|
if (! (pobj_convert_hash = hash_new (CONVERT_HASH_NBUCKEXP))) {
|
||||||
|
debug ("error: hash initialization failed");
|
||||||
|
debug ("...interrupted");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (count = 0, i = g_pobj_repo.occupied_head; i >= 0;
|
for (count = 0, i = g_pobj_repo.occupied_head; i >= 0;
|
||||||
count++, i = pobj_slot->next_index)
|
count++, i = pobj_slot->next_index)
|
||||||
{
|
{
|
||||||
pobj_slot = g_pobj_repo_list[POBJ_REPO_SEG (i)].list + POBJ_REPO_OFF (i);
|
pobj_slot = g_pobj_repo_list[POBJ_REPO_SEG (i)].list
|
||||||
pobj_restore (pobj_slot->objid, pobj_slot->size, &pobj_slot->rid,
|
+ POBJ_REPO_OFF (i);
|
||||||
pobj_convert_hash, xid);
|
objid = pobj_slot->objid;
|
||||||
|
size = pobj_slot->size;
|
||||||
|
|
||||||
|
debug ("restoring objid=%p size=%d (%d) rid={%d,%d,%ld}",
|
||||||
|
objid, size, POBJ_SIZE (size), pobj_slot->rid.page,
|
||||||
|
pobj_slot->rid.slot, pobj_slot->rid.size);
|
||||||
|
|
||||||
|
/* Allocate memory. */
|
||||||
|
p = (struct pobj *) g_memfunc.malloc (POBJ_SIZE (size));
|
||||||
|
if (! p) {
|
||||||
|
debug ("error :object allocation failed");
|
||||||
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
new_objid = POBJ2OBJ (p);
|
||||||
|
debug ("new object allocated at %p (%p)", new_objid, (void *) p);
|
||||||
|
|
||||||
|
/* Read object from backing store. */
|
||||||
|
Tread (xid, pobj_slot->rid, p);
|
||||||
|
|
||||||
|
debug ("inserting %p->%p conversion pair",
|
||||||
|
objid, new_objid);
|
||||||
|
|
||||||
|
/* Insert old/new objid pair to conversion table. */
|
||||||
|
if (hash_insert (pobj_convert_hash, OBJ2KEY (objid),
|
||||||
|
(unsigned long) new_objid) < 0) {
|
||||||
|
debug ("error: hash insertion failed");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (p)
|
||||||
|
g_memfunc.free (p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
debug ("...interrupted (%d object reconstructed)", count);
|
||||||
|
else
|
||||||
debug ("...done (%d objects reconstructed)", count);
|
debug ("...done (%d objects reconstructed)", count);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore static references repository.
|
* Restore static references repository.
|
||||||
*/
|
*/
|
||||||
|
if (! ret) {
|
||||||
debug ("restoring static references repository...");
|
debug ("restoring static references repository...");
|
||||||
|
|
||||||
debug ("restoring repository control block");
|
debug ("restoring repository control block");
|
||||||
|
@ -1656,11 +1675,13 @@ pobj_boot_restore (int xid)
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
XFREE (g_static_repo_list[i].list);
|
XFREE (g_static_repo_list[i].list);
|
||||||
XFREE (g_static_repo_list);
|
XFREE (g_static_repo_list);
|
||||||
}
|
g_static_repo_list = NULL;
|
||||||
debug_end ();
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug ("...interrupted");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
debug ("reading list segments...");
|
debug ("reading list segments...");
|
||||||
g_static_last_seg_rid = g_static_repo.first_seg_rid;
|
g_static_last_seg_rid = g_static_repo.first_seg_rid;
|
||||||
g_static_repo_list_max = 0;
|
g_static_repo_list_max = 0;
|
||||||
|
@ -1682,27 +1703,40 @@ pobj_boot_restore (int xid)
|
||||||
debug ("...done (%d segments read)", i);
|
debug ("...done (%d segments read)", i);
|
||||||
|
|
||||||
debug ("...done");
|
debug ("...done");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust references within objects.
|
* Adjust references within objects.
|
||||||
*/
|
*/
|
||||||
|
if (! ret) {
|
||||||
debug ("adjusting object references...");
|
debug ("adjusting object references...");
|
||||||
for (i = g_pobj_repo.occupied_head, count = 0; i >= 0;
|
for (i = g_pobj_repo.occupied_head, count = 0; i >= 0;
|
||||||
i = pobj_slot->next_index, count++) {
|
i = pobj_slot->next_index, count++) {
|
||||||
pobj_slot = g_pobj_repo_list[POBJ_REPO_SEG (i)].list + POBJ_REPO_OFF (i);
|
pobj_slot = g_pobj_repo_list[POBJ_REPO_SEG (i)].list + POBJ_REPO_OFF (i);
|
||||||
pobj_adjust (pobj_slot->objid, pobj_convert_hash, xid);
|
pobj_adjust (pobj_slot->objid, pobj_convert_hash, xid);
|
||||||
}
|
}
|
||||||
|
adjusted = 1;
|
||||||
debug ("...done (%d objects adjusted)", count);
|
debug ("...done (%d objects adjusted)", count);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust/tie static references to objects.
|
* Adjust/tie static references to objects.
|
||||||
*/
|
*/
|
||||||
|
if (! ret) {
|
||||||
debug ("tying adjusted static references, building fast lookup table...");
|
debug ("tying adjusted static references, building fast lookup table...");
|
||||||
g_static_repo_hash = hash_new (STATIC_REPO_HASH_NBUCKEXP);
|
|
||||||
tmp_rid.size = sizeof (struct static_repo_list_item);
|
|
||||||
for (i = g_static_repo.occupied_head; i >= 0; i = static_slot->next_index) {
|
|
||||||
static_slot = g_static_repo_list[STATIC_REPO_SEG(i)].list + STATIC_REPO_OFF(i);
|
|
||||||
|
|
||||||
|
if (! (g_static_repo_hash = hash_new (STATIC_REPO_HASH_NBUCKEXP))) {
|
||||||
|
debug ("error: hash initialization failed");
|
||||||
|
ret = -1;
|
||||||
|
debug ("...interrupted");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tmp_rid.size = sizeof (struct static_repo_list_item);
|
||||||
|
for (count = 0, i = g_static_repo.occupied_head; i >= 0;
|
||||||
|
count++, i = static_slot->next_index) {
|
||||||
|
static_slot = g_static_repo_list[STATIC_REPO_SEG(i)].list
|
||||||
|
+ STATIC_REPO_OFF(i);
|
||||||
new_objid = (void *) hash_lookup (pobj_convert_hash,
|
new_objid = (void *) hash_lookup (pobj_convert_hash,
|
||||||
OBJ2KEY (static_slot->objid));
|
OBJ2KEY (static_slot->objid));
|
||||||
|
|
||||||
|
@ -1714,18 +1748,84 @@ pobj_boot_restore (int xid)
|
||||||
/* Note: we apply a deliberate offset of 1 to index values,
|
/* Note: we apply a deliberate offset of 1 to index values,
|
||||||
* so as to be able to distinguish a 0 index value from "key not found"
|
* so as to be able to distinguish a 0 index value from "key not found"
|
||||||
* on subsequent table lookups. */
|
* on subsequent table lookups. */
|
||||||
hash_insert (g_static_repo_hash, OBJ2KEY (static_slot->static_ptr), i + 1);
|
if (hash_insert (g_static_repo_hash,
|
||||||
|
OBJ2KEY (static_slot->static_ptr), i + 1) < 0) {
|
||||||
|
debug ("error: hash insertion failed");
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tmp_rid.page = g_static_repo_list[STATIC_REPO_SEG(i)].rid.page;
|
tmp_rid.page = g_static_repo_list[STATIC_REPO_SEG(i)].rid.page;
|
||||||
tmp_rid.slot = i;
|
tmp_rid.slot = i;
|
||||||
Tset (xid, tmp_rid, static_slot);
|
Tset (xid, tmp_rid, static_slot);
|
||||||
changed++;
|
|
||||||
}
|
}
|
||||||
debug ("...done (%d tied)", changed);
|
if (ret < 0)
|
||||||
|
debug ("...interrupted");
|
||||||
|
else
|
||||||
|
debug ("...done (%d tied)", count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deconstruct everything in case of failure.
|
||||||
|
*/
|
||||||
|
if (ret < 0) {
|
||||||
|
if (g_static_repo_hash) {
|
||||||
|
debug ("nullifying static references and deallocating lookup table...");
|
||||||
|
for (i = g_static_repo.occupied_head; i >= 0;
|
||||||
|
i = static_slot->next_index) {
|
||||||
|
static_slot = g_static_repo_list[STATIC_REPO_SEG(i)].list
|
||||||
|
+ STATIC_REPO_OFF(i);
|
||||||
|
*static_slot->static_ptr = NULL;
|
||||||
|
}
|
||||||
|
hash_free (g_static_repo_hash);
|
||||||
|
g_static_repo_hash = NULL;
|
||||||
|
debug ("...done");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_static_repo_list) {
|
||||||
|
debug ("deallocating static references repository...");
|
||||||
|
for (i = 0; i < g_static_repo.nseg; i++)
|
||||||
|
XFREE (g_static_repo_list[i].list);
|
||||||
|
XFREE (g_static_repo_list);
|
||||||
|
g_static_repo_list = NULL;
|
||||||
|
debug ("...done");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pobj_convert_hash) {
|
||||||
|
debug ("deallocating persistent objects...");
|
||||||
|
for (count = 0, i = g_pobj_repo.occupied_head; i >= 0;
|
||||||
|
count++, i = pobj_slot->next_index) {
|
||||||
|
pobj_slot = g_pobj_repo_list[POBJ_REPO_SEG (i)].list
|
||||||
|
+ POBJ_REPO_OFF (i);
|
||||||
|
if (adjusted)
|
||||||
|
new_objid = pobj_slot->objid;
|
||||||
|
else
|
||||||
|
new_objid = (void *) hash_lookup (pobj_convert_hash,
|
||||||
|
OBJ2KEY (pobj_slot->objid));
|
||||||
|
if (new_objid) {
|
||||||
|
p = OBJ2POBJ (new_objid);
|
||||||
|
debug ("deallocating %p (%p)", new_objid, (void *) p);
|
||||||
|
g_memfunc.free (p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug ("...done (%d object deallocated)", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug ("deallocating object repository...");
|
||||||
|
for (i = 0; i < g_pobj_repo.nseg; i++)
|
||||||
|
XFREE (g_pobj_repo_list[i].list);
|
||||||
|
XFREE (g_pobj_repo_list);
|
||||||
|
g_pobj_repo_list = NULL;
|
||||||
|
debug ("...done");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pobj_convert_hash)
|
||||||
hash_free (pobj_convert_hash);
|
hash_free (pobj_convert_hash);
|
||||||
debug_end ();
|
debug_end ();
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1740,25 +1840,57 @@ pobj_boot_init (int xid)
|
||||||
debug_start ();
|
debug_start ();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a single-segment persistent object repository.
|
* Allocate memory for single-segment object/static repositories and
|
||||||
|
* fast lookup table.
|
||||||
*/
|
*/
|
||||||
debug ("creating persistent object repository...");
|
debug ("allocating memory for repositories and fast lookup table...");
|
||||||
|
|
||||||
debug ("allocating memory");
|
|
||||||
g_pobj_repo_list = (struct pobj_repo_list *)
|
g_pobj_repo_list = (struct pobj_repo_list *)
|
||||||
XMALLOC (sizeof (struct pobj_repo_list));
|
XMALLOC (sizeof (struct pobj_repo_list));
|
||||||
if (g_pobj_repo_list)
|
if (g_pobj_repo_list)
|
||||||
g_pobj_repo_list[0].list = (struct pobj_repo_list_item *)
|
g_pobj_repo_list[0].list = (struct pobj_repo_list_item *)
|
||||||
XMALLOC (sizeof (struct pobj_repo_list_item) * POBJ_REPO_SEG_MAX);
|
XMALLOC (sizeof (struct pobj_repo_list_item) * POBJ_REPO_SEG_MAX);
|
||||||
if (! (g_pobj_repo_list && g_pobj_repo_list[0].list)) {
|
|
||||||
|
g_static_repo_list = (struct static_repo_list *)
|
||||||
|
XMALLOC (sizeof (struct static_repo_list));
|
||||||
|
if (g_static_repo_list)
|
||||||
|
g_static_repo_list[0].list = (struct static_repo_list_item *)
|
||||||
|
XMALLOC (sizeof (struct static_repo_list_item) * STATIC_REPO_SEG_MAX);
|
||||||
|
|
||||||
|
g_static_repo_hash = hash_new (STATIC_REPO_HASH_NBUCKEXP);
|
||||||
|
|
||||||
|
if (! (g_pobj_repo_list && g_pobj_repo_list[0].list
|
||||||
|
&& g_static_repo_list && g_static_repo_list[0].list
|
||||||
|
&& g_static_repo_hash))
|
||||||
|
{
|
||||||
debug ("error: allocation failed");
|
debug ("error: allocation failed");
|
||||||
if (g_pobj_repo_list)
|
|
||||||
|
if (g_pobj_repo_list) {
|
||||||
|
if (g_pobj_repo_list[0].list)
|
||||||
|
XFREE (g_pobj_repo_list[0].list);
|
||||||
XFREE (g_pobj_repo_list);
|
XFREE (g_pobj_repo_list);
|
||||||
|
}
|
||||||
|
if (g_static_repo_list) {
|
||||||
|
if (g_static_repo_list[0].list)
|
||||||
|
XFREE (g_static_repo_list[0].list);
|
||||||
|
XFREE (g_static_repo_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_static_repo_hash)
|
||||||
|
hash_free (g_static_repo_hash);
|
||||||
|
|
||||||
debug_end ();
|
debug_end ();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug ("initializing in-memory single-segment object list");
|
debug ("...done");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize persistent object repository.
|
||||||
|
*/
|
||||||
|
debug ("creating persistent object repository...");
|
||||||
|
|
||||||
|
debug ("initializing single-segment list");
|
||||||
/* Note: don't care for back pointers in vacant list. */
|
/* Note: don't care for back pointers in vacant list. */
|
||||||
pobj_slot = g_pobj_repo_list[0].list;
|
pobj_slot = g_pobj_repo_list[0].list;
|
||||||
next_index = 1;
|
next_index = 1;
|
||||||
|
@ -1798,25 +1930,11 @@ pobj_boot_init (int xid)
|
||||||
debug ("...done");
|
debug ("...done");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a single-segment static reference repository.
|
* Initialize static reference repository.
|
||||||
*/
|
*/
|
||||||
debug ("creating static reference repository...");
|
debug ("creating static reference repository...");
|
||||||
|
|
||||||
debug ("allocating memory");
|
debug ("initializing single-segment list");
|
||||||
g_static_repo_list = (struct static_repo_list *)
|
|
||||||
XMALLOC (sizeof (struct static_repo_list));
|
|
||||||
if (g_static_repo_list)
|
|
||||||
g_static_repo_list[0].list = (struct static_repo_list_item *)
|
|
||||||
XMALLOC (sizeof (struct static_repo_list_item) * STATIC_REPO_SEG_MAX);
|
|
||||||
if (! (g_static_repo_list && g_static_repo_list[0].list)) {
|
|
||||||
debug ("error: allocation failed");
|
|
||||||
if (g_static_repo_list)
|
|
||||||
XFREE (g_static_repo_list);
|
|
||||||
debug_end ();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug ("initializing in-memory single-segment static reference list");
|
|
||||||
/* Note: don't care for back pointers in vacant list. */
|
/* Note: don't care for back pointers in vacant list. */
|
||||||
static_slot = g_static_repo_list[0].list;
|
static_slot = g_static_repo_list[0].list;
|
||||||
next_index = 1;
|
next_index = 1;
|
||||||
|
@ -1853,11 +1971,11 @@ pobj_boot_init (int xid)
|
||||||
g_boot.static_repo_rid = Talloc (xid, sizeof (struct repo));
|
g_boot.static_repo_rid = Talloc (xid, sizeof (struct repo));
|
||||||
Tset (xid, g_boot.static_repo_rid, &g_static_repo);
|
Tset (xid, g_boot.static_repo_rid, &g_static_repo);
|
||||||
|
|
||||||
g_static_repo_hash = hash_new (STATIC_REPO_HASH_NBUCKEXP);
|
|
||||||
|
|
||||||
debug ("...done");
|
debug ("...done");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize boot record.
|
||||||
|
*/
|
||||||
debug ("writing boot record...");
|
debug ("writing boot record...");
|
||||||
Tset (xid, g_boot_rid, &g_boot);
|
Tset (xid, g_boot_rid, &g_boot);
|
||||||
debug ("...done");
|
debug ("...done");
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct queue_seg {
|
||||||
struct queue {
|
struct queue {
|
||||||
struct queue_seg *head_seg;
|
struct queue_seg *head_seg;
|
||||||
struct queue_seg *tail_seg;
|
struct queue_seg *tail_seg;
|
||||||
|
struct queue_seg *recycle_seg;
|
||||||
int seg_size;
|
int seg_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ queue_new (int seg_size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q->recycle_seg = NULL;
|
||||||
q->seg_size = seg_size;
|
q->seg_size = seg_size;
|
||||||
debug_end ();
|
debug_end ();
|
||||||
return q;
|
return q;
|
||||||
|
@ -66,6 +68,8 @@ queue_free (struct queue *q)
|
||||||
next = seg->next;
|
next = seg->next;
|
||||||
XFREE (seg);
|
XFREE (seg);
|
||||||
}
|
}
|
||||||
|
if (q->recycle_seg)
|
||||||
|
XFREE (q->recycle_seg);
|
||||||
XFREE (q);
|
XFREE (q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +99,18 @@ queue_deq (struct queue *q)
|
||||||
if (seg->head == q->seg_size)
|
if (seg->head == q->seg_size)
|
||||||
seg->head = 0;
|
seg->head = 0;
|
||||||
|
|
||||||
/* Deallocate empty head segment, if it isn't the last one. */
|
/* Deallocate empty head segment, if it isn't the last one.
|
||||||
|
* Note: we "recycle" a single segment, to avoid repeated allocation /
|
||||||
|
* deallocation when a contant length cyclic enq/deq sequence is due. */
|
||||||
if (seg->head == seg->tail && seg->next) {
|
if (seg->head == seg->tail && seg->next) {
|
||||||
q->head_seg = seg->next;
|
q->head_seg = seg->next;
|
||||||
|
if (q->recycle_seg)
|
||||||
XFREE (seg);
|
XFREE (seg);
|
||||||
|
else {
|
||||||
|
debug ("recycling seg=%p", seg);
|
||||||
|
memset (seg, 0, sizeof (struct queue_seg));
|
||||||
|
q->recycle_seg = seg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_end ();
|
debug_end ();
|
||||||
|
@ -123,6 +135,12 @@ queue_enq (struct queue *q, unsigned long val)
|
||||||
|
|
||||||
/* Allocate new segment if current was exhausted. */
|
/* Allocate new segment if current was exhausted. */
|
||||||
if (seg->head == seg->tail) {
|
if (seg->head == seg->tail) {
|
||||||
|
if (q->recycle_seg) {
|
||||||
|
debug ("using recycled segment seg=%p", q->recycle_seg);
|
||||||
|
seg->next = q->recycle_seg;
|
||||||
|
q->recycle_seg = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
seg->next = queue_seg_alloc (q->seg_size);
|
seg->next = queue_seg_alloc (q->seg_size);
|
||||||
if (! seg->next) {
|
if (! seg->next) {
|
||||||
if (! seg->tail--)
|
if (! seg->tail--)
|
||||||
|
@ -131,6 +149,7 @@ queue_enq (struct queue *q, unsigned long val)
|
||||||
debug_end ();
|
debug_end ();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
q->tail_seg = seg->next;
|
q->tail_seg = seg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue