* room_ops.c: increased the thread safety of cgetfloor()
authorArt Cancro <ajc@citadel.org>
Sun, 21 Mar 2004 22:32:24 +0000 (22:32 +0000)
committerArt Cancro <ajc@citadel.org>
Sun, 21 Mar 2004 22:32:24 +0000 (22:32 +0000)
* housekeeping.c: check floor reference counts in two passes instead of
  trying to manipulate multiple tables in O^2

citadel/ChangeLog
citadel/housekeeping.c
citadel/room_ops.c
citadel/server.h

index 8f8749044d5cd7ad77dca4be1e8e6c8feea70338..90c622f904bb03aefdd896d9ccb6e22a73dd3b26 100644 (file)
@@ -1,4 +1,9 @@
  $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
@@ -5565,3 +5570,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
+
index c60bcbf94da28dd46ddc804d236c5737a9f537d7..da86e19c3776b9adb5b78753c6691338b9f45520 100644 (file)
@@ -90,33 +90,43 @@ void check_sched_shutdown(void) {
 /*
  * 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]);
+       }
 }      
 
 /*
index 2b80cabae660df0fc16f066de762ac9edbc49721..242025627fc5588cce0af02d59bdadb18cbfa8b4 100644 (file)
@@ -333,17 +333,31 @@ void lgetfloor(struct floor *flbuf, int floor_num)
 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]);
@@ -356,14 +370,17 @@ struct floor *cgetfloor(int 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));
 }
 
 
@@ -1692,7 +1709,12 @@ void cmd_cre8(char *args)
 
        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;
index c72f849f1f593b6311e4344ff9ad3fbfae3f5759..8c42ec21c95eb35fd08ac4710fde0fef9f53feb2 100644 (file)
@@ -215,6 +215,7 @@ enum {
        S_NETCONFIGS,
        S_PUBLIC_CLIENTS,
        S_LDAP,
+       S_FLOORCACHE,
        MAX_SEMAPHORES
 };