$Log$
+ Revision 614.90 2004/03/21 22:32:24 ajc
+ * room_ops.c: increased the thread safety of cgetfloor()
+ * housekeeping.c: check floor reference counts in two passes instead of
+ trying to manipulate multiple tables in O^2
+
Revision 614.89 2004/03/21 17:14:46 error
* stress.c: Fixed. Now properly spawns threads and stresses out your
favorite Citadel server by simulating large numbers of really active
Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
* Initial CVS import
+
/*
* Check (and fix) floor reference counts. This doesn't need to be done
* very often, since the counts should remain correct during normal operation.
- * NOTE: this function pair should ONLY be called during startup. It is NOT
- * thread safe.
*/
void check_ref_counts_backend(struct ctdlroom *qrbuf, void *data) {
- struct floor flbuf;
- getfloor(&flbuf, qrbuf->QRfloor);
- ++flbuf.f_ref_count;
- flbuf.f_flags = flbuf.f_flags | QR_INUSE;
- putfloor(&flbuf, qrbuf->QRfloor);
+ int *new_refcounts;
+
+ new_refcounts = (int *) data;
+
+ ++new_refcounts[(int)qrbuf->QRfloor];
}
void check_ref_counts(void) {
struct floor flbuf;
int a;
+ int new_refcounts[MAXFLOORS];
+
lprintf(CTDL_DEBUG, "Checking floor reference counts\n");
for (a=0; a<MAXFLOORS; ++a) {
- getfloor(&flbuf, a);
- flbuf.f_ref_count = 0;
- flbuf.f_flags = flbuf.f_flags & ~QR_INUSE;
- putfloor(&flbuf, a);
+ new_refcounts[a] = 0;
}
cdb_begin_transaction();
- ForEachRoom(check_ref_counts_backend, NULL);
+ ForEachRoom(check_ref_counts_backend, (void *)new_refcounts );
cdb_end_transaction();
+
+ for (a=0; a<MAXFLOORS; ++a) {
+ lgetfloor(&flbuf, a);
+ flbuf.f_ref_count = new_refcounts[a];
+ if (new_refcounts[a] > 0) {
+ flbuf.f_flags = flbuf.f_flags | QR_INUSE;
+ }
+ else {
+ flbuf.f_flags = flbuf.f_flags & ~QR_INUSE;
+ }
+ lputfloor(&flbuf, a);
+ lprintf(9, "Floor %d: %d rooms\n", a, new_refcounts[a]);
+ }
}
/*
struct floor *cgetfloor(int floor_num) {
static int initialized = 0;
int i;
+ int fetch_new = 0;
+ struct floor *fl = NULL;
+ begin_critical_section(S_FLOORCACHE);
if (initialized == 0) {
for (i=0; i<MAXFLOORS; ++i) {
floorcache[floor_num] = NULL;
}
initialized = 1;
}
-
if (floorcache[floor_num] == NULL) {
- floorcache[floor_num] = mallok(sizeof(struct floor));
- getfloor(floorcache[floor_num], floor_num);
+ fetch_new = 1;
+ }
+ end_critical_section(S_FLOORCACHE);
+
+ if (fetch_new) {
+ lprintf(9, "fetch_new is active ... going to disk\n");
+ fl = mallok(sizeof(struct floor));
+ getfloor(fl, floor_num);
+ begin_critical_section(S_FLOORCACHE);
+ if (floorcache[floor_num] != NULL) {
+ phree(floorcache[floor_num]);
+ }
+ floorcache[floor_num] = fl;
+ end_critical_section(S_FLOORCACHE);
}
return(floorcache[floor_num]);
*/
void putfloor(struct floor *flbuf, int floor_num)
{
- cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
- flbuf, sizeof(struct floor));
-
/* If we've cached this, clear it out, 'cuz it's WRONG now! */
+ begin_critical_section(S_FLOORCACHE);
if (floorcache[floor_num] != NULL) {
phree(floorcache[floor_num]);
- floorcache[floor_num] = NULL;
+ floorcache[floor_num] = mallok(sizeof(struct floor));
+ memcpy(floorcache[floor_num], flbuf, sizeof(struct floor));
}
+ end_critical_section(S_FLOORCACHE);
+
+ cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
+ flbuf, sizeof(struct floor));
}
if (num_parms(args) >= 5) {
fl = cgetfloor(extract_int(args, 4));
- if ((fl->f_flags & F_INUSE) == 0) {
+ if (fl == NULL) {
+ cprintf("%d Invalid floor number.\n",
+ ERROR + INVALID_FLOOR_OPERATION);
+ return;
+ }
+ else if ((fl->f_flags & F_INUSE) == 0) {
cprintf("%d Invalid floor number.\n",
ERROR + INVALID_FLOOR_OPERATION);
return;