libsrc/bert.cxx

Go to the documentation of this file.
00001 /**********************************************************************
00002  * Copyright 2002 Jeff Rush <jrush@taupro.com>
00003  * Original Copyright 1979-2002 Udanax.com
00004  *
00005  * This file is part of the Udanax xanalogical storage system.
00006  *
00007  * Udanax is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * Udanax is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with Udanax; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  **********************************************************************/
00021 
00030 /* Modification History:
00031  * $Log: bert.cxx,v $
00032  * Revision 1.17  2004/09/11 13:59:21  jrush
00033  * Changed all fprintf's to stderr to use the Nana library L() macro.  Also
00034  * removed a 2-3 minor compiler warnings.
00035  *
00036  * Revision 1.16  2004/09/04 16:02:17  jrush
00037  * Added Doxygen headers before each and every function definition.
00038  *
00039  * Revision 1.15  2004/08/28 13:35:26  jrush
00040  * Catching up CVS to various incomplete versions on local disk.
00041  *
00042  * Revision 1.14  2002/07/26 04:30:29  jrush
00043  * Replaced gerror() with assert()
00044  *
00045  * Revision 1.13  2002/05/28 04:22:29  jrush
00046  * Adjusted source files to comply with GPL licensing.
00047  *
00048  * Revision 1.12  2002/05/28 02:49:42  jrush
00049  * Made static any functions and global variables private to this source file
00050  * and commented out any unused functions.
00051  *
00052  * Revision 1.11  2002/04/13 13:09:40  jrush
00053  * Convert typedef of struct into just struct, for C++ style.
00054  *
00055  * Revision 1.10  2002/04/12 11:56:42  jrush
00056  * Reorganized include file layout, renamed xanadu.h to udanax.h and
00057  * typecontext/typecrumcontext to C++ class Context/CrumContext.
00058  *
00059  * Revision 1.9  2002/04/10 18:01:54  jrush
00060  * Renamed class typeisa to IStreamAddr.
00061  *
00062  * Revision 1.8  2002/04/09 21:45:46  jrush
00063  * Renamed class 'tumbler' to 'Tumbler', for consistency with Python sources,
00064  * and changed typeisa from typedef to a subclass, in preparation for cleaning
00065  * up the type/class tree.
00066  *
00067  * Revision 1.7  2002/04/08 18:55:56  jrush
00068  * Switched from using global variable 'user' to object 'Session' as a
00069  * connection for tracking open document descriptors in the bert table.
00070  *
00071  * Revision 1.6  2002/04/07 14:02:28  jrush
00072  * Restored large tabular comments garbled during source indent operation.
00073  * Also added code in a few places to stuff meaningful errorcodes into the
00074  * Session structure upon API failure.
00075  *
00076  * Revision 1.5  2002/04/06 17:05:57  jrush
00077  * Switched from referring to 'task' for a client connection to 'session',
00078  * and converted the typetask typedef/struct into a Session C++ class.
00079  *
00080  * Revision 1.4  2002/04/06 15:01:17  jrush
00081  * Changed INT to just 'int'.
00082  *
00083  * Revision 1.3  2002/04/02 18:44:16  jrush
00084  * Redefined hashoftumbler() to be static, and then some cosmetic changes.
00085  *
00086  * Revision 1.2  2002/02/14 09:27:43  jrush
00087  * Cleaned up source:
00088  *
00089  * 1. ran thru the indent tool to achieve a standard look,
00090  * 2. added structured comments at top for use with DOxygen reporting
00091  *    as well as CVS keywords,
00092  * 3. fixed compiler warnings re ambiguous assign/compares,
00093  *    needed casts and unused/uninitialized variables,
00094  * 4. fixed funcs that didn't specify a return type,
00095  * 5. centralized prototypes in protos.h, removing incomplete ones,
00096  * 6. cleaned up use of bool/BOOLEAN type to suit C++ type,
00097  * 7. fixed initializer nesting in tumbler constants,
00098  * 8. renamed vars that conflict with C++ keywords (new, this),
00099  * 9. fixed global/extern confusion re some global vars.
00100  *
00101  */
00102 
00103 #include "udanax.h"
00104 
00105 struct bertentry {
00106     Session    *sess;       
00107     Tumbler     documentid; // ID of document that was opened
00108     char        created;
00109     char        modified;
00110     int         type;
00111     int         count;
00112 };
00113 
00114 struct conscell {
00115     conscell   *next;
00116     bertentry  *stuff;
00117 };
00118 
00119 static const int primes[] = {
00120       3,   7,  11,  17,  37,  41,  59,  71,  97,  103,
00121     113, 131, 151, 137, 277, 421, 433, 567, 643,  743
00122 };
00123 
00124 #define NUMBEROFBERTTABLE 1327
00125 
00126 static conscell *berttable[NUMBEROFBERTTABLE];
00127 
00128 #ifndef DISTRIBUTION
00129 //UNUSED static char *bertModeNames[] = { "BADMODE", "ONLY", "COPYIF", "COPY" };
00130 static char *bertTypeNames[] = { "NOBERT", "READBERT", "WRITEBERT" };
00131 //UNUSED char bertMsgBuf[256] = "";
00132 #endif
00133 
00141     static unsigned int
00142 hashoftumbler(
00143     Tumbler *tp)
00144 {
00145     unsigned int ret = tp->exp;
00146 
00147     for (int i = 0; i < NPLACES; i++)
00148         ret += (unsigned int) tp->mantissa[i] * primes[i];
00149 
00150     return ret % NUMBEROFBERTTABLE;
00151 }
00152 
00160 /*  checkforopen
00161  *      Returns:  >0 for sufficiently open
00162  *                      integer indicates type of open
00163  *                0 if open required
00164  *               -1 if new version should be made
00165  *
00166  *      Open state -->
00167  *      type                Not Open    #   Open READ   #  Open WRITE
00168  *        |             !owned  | owned #conn== |conn!= #conn== |conn!=
00169  *        v             --------+-------#-------+-------#-------+-------
00170  *      READ               0    |   0   #  READ |   0   # WRITE | -1
00171  *      ------------------------+-------#-------+-------#-------+-------
00172  *      WRITE             -1    |   0   #  -1   |  -1   # WRITE | -1
00173  *      
00174  */
00175     int
00176 checkforopen(
00177     Session *sess,          
00178     Tumbler *tp,
00179     int      type)
00180 {
00181     int foundnonread = false;
00182 
00183     if (type == NOBERTREQUIRED)
00184         return 1;                      /* Random > 0 */
00185 
00186     conscell *p;
00187     for (p = berttable[hashoftumbler(tp)]; p && p->stuff; p = p->next) {
00188         bertentry *bert = p->stuff;
00189 
00190         if (tumblereq(tp, &bert->documentid)) {
00191             if (sess == bert->sess) {
00192                 switch (bert->type) {
00193                 case READBERT:
00194                     return (type == READBERT) ? READBERT : /* WRITE */ -1;
00195                 case WRITEBERT:
00196                     return WRITEBERT;
00197                 }
00198             } else {
00199                 if (bert->type != READBERT) {
00200                     foundnonread = true;
00201                 }
00202             }
00203         }
00204     }
00205 
00206     if (!foundnonread && (type == READBERT || isthisusersdocument(sess, tp)))
00207         return 0;
00208     else
00209         return -1;
00210 }
00211 
00219     void
00220 logbertmodifiedforcrum(
00221     Session *sess,          
00222     typecuc *crumptr)
00223 {
00224 /* logbertmodified(xxx); */
00225 }
00226 
00234     void
00235 logbertmodified(
00236     Session *sess,          
00237     Tumbler *tp)
00238 {
00239     /* L("logbertmodified sess= %d bert= ", (int) sess);dumptumbler(tp); L("\n"); */
00240 
00241     conscell *p;
00242     for (p = berttable[ hashoftumbler(tp) ]; p && p->stuff; p = p->next) {
00243         bertentry *bert = (bertentry *) p->stuff;
00244         if (bert->sess == sess && tumblereq(tp, &bert->documentid)) {
00245             bert->modified = true;
00246             return;
00247         }
00248     }
00249 }
00250 
00258     static void
00259 incrementopen(
00260     Session *sess,          
00261     Tumbler *tp)
00262 {
00263 #ifndef DISTRIBUTION
00264     L("incrementopen:  sess = %d  tp = ", (int) sess);
00265     dumptumbler(tp);
00266     L("\n");
00267 #endif
00268 
00269     conscell *p;
00270     for (p = berttable[ hashoftumbler(tp) ]; p && p->stuff; p = p->next) {
00271         bertentry *bert = (bertentry *) p->stuff;
00272         if (bert->sess == sess && tumblereq(tp, &bert->documentid))
00273             bert->count += 1;
00274     }
00275 }
00276 
00284     static void
00285 addtoopen(
00286     Session *sess,          
00287     Tumbler *tp,
00288     int      created,
00289     int      type)
00290 {
00291 #ifndef DISTRIBUTION
00292     L("addtoopen:  sess = %d  type = %s  created = %d  tp = ", (int) sess, bertTypeNames[type], created);
00293     dumptumbler(tp);
00294     L("\n");
00295 #endif
00296 
00297     int hash = hashoftumbler(tp);
00298 
00299 /* these eallocwithtags changed to malloc by hill zzzz */
00300 
00301     bertentry *ptr;
00302     if ((ptr = (bertentry *) eallocwithtag(sizeof(bertentry), BERTTAG)) == NULL)
00303         assert(0); // out of memory
00304 
00305     tumblercopy(tp, &ptr->documentid);
00306 
00307     ptr->sess       = sess;
00308     ptr->count      = 1;
00309     ptr->created    = created;
00310     ptr->modified   = false;
00311     ptr->type       = type;
00312 
00313     conscell *consp;
00314     if ((consp = (conscell *) eallocwithtag(sizeof(conscell), BERTCONSCELLTAG)) == NULL)
00315         assert(0); // out of memory
00316 
00317     consp->stuff    = ptr;
00318     consp->next     = berttable[hash];
00319     berttable[hash] = consp;
00320 }
00321 
00329     static void
00330 deleteversion(
00331     Tumbler *tp)
00332 {
00333 #ifndef DISTRIBUTION
00334     L("deleteversion: tp = ");
00335     dumptumbler(tp);
00336     L("\n");
00337 #endif
00338 }
00339 
00347     static bool
00348 removefromopen(
00349     Session *sess,          
00350     Tumbler *tp)
00351 {
00352 #ifndef DISTRIBUTION
00353     L("removefromopen:  sess = %d  tp = ", (int) sess);
00354     dumptumbler(tp);
00355     L("\n");
00356 #endif
00357 
00358     int hash = hashoftumbler(tp);
00359     conscell *oldptr = NULL;
00360 
00361     conscell *p;
00362     for (p = berttable[hash]; p && p->stuff; p = p->next) {
00363         bertentry *bert = p->stuff;
00364         if (bert->sess == sess && tumblereq(tp, &bert->documentid)) {
00365             if (--bert->count)
00366                 return true;
00367 
00368             /* status = bert->modified && bert->created ; */
00369             int status = bert->created && !bert->modified;
00370             if (status)
00371                 deleteversion(tp);
00372 
00373             efree((char *) p->stuff);
00374 
00375             conscell *temp;
00376             if (oldptr == NULL) {
00377                 temp = berttable[hash];
00378                 berttable[hash] = berttable[hash]->next;
00379                 efree((char *)temp);
00380                 return true;
00381             } else {
00382                 temp = oldptr->next;
00383                 oldptr->next = p->next;
00384                 efree((char *)temp);
00385                 return true;
00386             }
00387         }
00388         oldptr = p;
00389     }
00390     return false;
00391 }
00392 
00400     void
00401 closeberts(
00402     Session *sess)          
00403 {
00404 #ifndef DISTRIBUTION
00405     L("closeberts:  sess = 0x%08lX\n", (int) sess);
00406 #endif
00407 
00408     conscell *oldptr = NULL;
00409     int i;
00410     for (i = 0; i < NUMBEROFBERTTABLE; i++) {
00411         conscell *p;
00412         for (p = berttable[i]; p && p->stuff; p = p->next) {
00413             bertentry *bert = p->stuff;
00414             if (bert->sess == sess) {
00415                 int status = bert->modified && bert->created;
00416                 if (status)
00417                     deleteversion(&bert->documentid);
00418 
00419                 efree((char *)p->stuff);
00420 
00421                 conscell *temp;
00422                 if (oldptr == NULL) {
00423                     temp = berttable[i];
00424                     berttable[i] = berttable[i]->next;
00425                     efree((char *) temp);
00426                     return;
00427                 } else {
00428                     temp = oldptr->next;
00429                     oldptr->next = p->next;
00430                     efree((char *) temp);
00431                     return;
00432                 }
00433             }
00434             oldptr = p;
00435         }
00436     }
00437 }
00438 
00446 /*
00447  *      Open state -->
00448  *      type & mode          Not Open   #   Open READ   #   Open WRITE
00449  *        |             !owned  | owned #conn== |conn!= #conn== |conn!=
00450  *        v             ========+=======#=======+=======#=======+=======
00451  *              read       0    |   0   #   0   |   0   #  -1   |   -1
00452  *      COPYIF  ----------------+-------#-------+-------#-------+-------
00453  *              write     -1    |   0   #  -1   |  -1   #  -1   |   -1
00454  *              ================+=======#=======+=======#=======+=======
00455  *              read       0    |   0   #   0   |   0   #   X   |    X
00456  *      ONLY    ----------------+-------#-------+-------#-------+-------
00457  *              write      X    |   0   #   X   |   X   #   X   |    X
00458  *              ================+=======#=======+=======#=======+=======
00459  *              read      -1    |  -1   #  -1   |  -1   #  -1   |   -1
00460  *      COPY    ----------------+-------#-------+-------#-------+-------
00461  *              write     -1    |  -1   #  -1   |  -1   #  -1   |   -1
00462  *
00463  */
00464     bool
00465 doopen(
00466     Session     *sess,          
00467     IStreamAddr *tp,
00468     IStreamAddr *newtp,
00469     int          type,
00470     int          mode)
00471 {
00472     L("Entered doopen()\n");
00473 
00474     if (type == NOBERTREQUIRED)
00475         return true;
00476 
00477     L("type != NOBERTREQUIRED\n");
00478 
00479     if (mode == BERTMODECOPY) {
00480         L("mode == BERTMODECOPY, trying to copy document\n");
00481 
00482         if (docreatenewversion(sess, tp, &sess->account, newtp)) {
00483             addtoopen(sess, newtp, true, type);
00484             return true;
00485         } else {
00486             sess->errorcode = ERR_OPEN_COPY; // Attempt to make a copy to open failed
00487             return false;
00488         }
00489     }
00490 
00491     L("about to call checkforopen()\n");
00492 
00493     int openState = checkforopen(sess, tp, type);
00494 
00495     L("returned from call to checkforopen(), openState = %d\n", openState);
00496 
00497     if (openState == 0) {
00498         L("already open in R/O, just trying to inc open count\n");
00499 
00500         addtoopen(sess, tp, false, type);
00501         tumblercopy(tp, newtp);
00502         return true;
00503     }
00504 
00505     switch (mode) {
00506     case BERTMODECOPYIF:
00507         if (openState == -1) { // Document not already open
00508             if (docreatenewversion(sess, tp, &sess->account, newtp)) {
00509                 addtoopen(sess, newtp, true, type);
00510             } else {
00511                 sess->errorcode = ERR_OPEN_COPY; // Attempt to make a copy to open failed
00512                 return false;
00513             }
00514 
00515         } else if (type != WRITEBERT && openState != WRITEBERT) { // Open another Shared Read-Open Reference
00516             incrementopen(sess, tp);
00517             tumblercopy(tp, newtp);
00518 
00519         } else { // Document is already open, Open a new copy
00520             docreatenewversion(sess, tp, &sess->account, newtp);
00521             addtoopen(sess, newtp, true, type);
00522         }
00523         return true;
00524 
00525     case BERTMODEONLY:
00526         if (openState == -1 || type == WRITEBERT || openState == WRITEBERT) {
00527             return false;
00528         } else {
00529             incrementopen(sess, tp);
00530             tumblercopy(tp, newtp);
00531             return true;
00532         }
00533 
00534     default:
00535         assert(0); // DEFAULT CASE IN DOOPEN
00536         return false;
00537     }
00538 }
00539 
00547     bool
00548 doclose(
00549     Session     *sess,          
00550     IStreamAddr *tp)
00551 {
00552 #ifndef DISTRIBUTION
00553     L("doclose: sess = %d  tp = ", (int) sess);
00554     dumptumbler(tp);
00555     L("\n");
00556 #endif
00557 
00558     if (!removefromopen(sess, tp)) {
00559         sess->errorcode = ERR_CLOSE_WO_OPEN; // Attempted close of a document that was never opened
00560         return false;
00561     }
00562 
00563     return true;                       /* for now, so as to not upset front-end */
00564 }

Generated on Sun Aug 21 04:18:13 2005 for Udanax-Green by doxygen1.3.4