00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 #include "udanax.h"
00104
00105 struct bertentry {
00106 Session *sess;
00107 Tumbler documentid;
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
00130 static char *bertTypeNames[] = { "NOBERT", "READBERT", "WRITEBERT" };
00131
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
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
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;
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 : -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
00225 }
00226
00234 void
00235 logbertmodified(
00236 Session *sess,
00237 Tumbler *tp)
00238 {
00239
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
00300
00301 bertentry *ptr;
00302 if ((ptr = (bertentry *) eallocwithtag(sizeof(bertentry), BERTTAG)) == NULL)
00303 assert(0);
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);
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
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
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
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;
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) {
00508 if (docreatenewversion(sess, tp, &sess->account, newtp)) {
00509 addtoopen(sess, newtp, true, type);
00510 } else {
00511 sess->errorcode = ERR_OPEN_COPY;
00512 return false;
00513 }
00514
00515 } else if (type != WRITEBERT && openState != WRITEBERT) {
00516 incrementopen(sess, tp);
00517 tumblercopy(tp, newtp);
00518
00519 } else {
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);
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;
00560 return false;
00561 }
00562
00563 return true;
00564 }