1 /* ============================================================
3 * - single thread commit on local machine
4 * =============================================================
5 * Copyright (c) 2009, University of California, Irvine, USA.
9 * =============================================================
17 /* Per thread transaction variables */
18 __thread objstr_t *t_cache;
19 __thread objstr_t *t_reserve;
20 __thread struct objlist * newobjs;
27 #include "delaycomp.h"
28 __thread struct pointerlist ptrstack;
29 __thread struct primitivelist primstack;
30 __thread struct branchlist branchstack;
31 struct pointerlist *c_ptrstack;
32 struct primitivelist *c_primstack;
33 struct branchlist *c_branchstack;
37 int numTransCommit = 0;
38 int numTransAbort = 0;
40 int nSoftAbortCommit = 0;
41 int nSoftAbortAbort = 0;
45 /* Thread variable for locking/unlocking */
46 __thread threadrec_t *trec;
47 __thread struct objlist * lockedobjs;
48 __thread int t_objnumcount=0;
50 /* Collect stats for object classes causing abort */
51 objtypestat_t typesCausingAbort[TOTALNUMCLASSANDARRAY];
54 * Inline fuction to get Transaction size per object type for those
59 INLINE void getTransSize(objheader_t *header , int *isObjTypeTraverse) {
60 (typesCausingAbort[TYPE(header)]).numabort++;
61 if(isObjTypeTraverse[TYPE(header)] != 1) {
62 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
63 (typesCausingAbort[TYPE(header)]).numtrans+=1; //should this count be kept per object
65 isObjTypeTraverse[TYPE(header)]=1;
67 #define DEBUGSTMSTAT(args...)
69 #define DEBUGSTMSTAT(args...)
73 #define DEBUGSTM(x...) printf(x);
75 #define DEBUGSTM(x...);
79 #define DEBUGSTATS(x...) printf(x);
81 #define DEBUGSTATS(x...);
85 //void * A_memcpy (void * dest, const void * src, size_t count);
87 //#define A_memcpy memcpy
90 void * A_memcpy (void * dest, const void * src, size_t count) {
92 INTPTR *desti=(INTPTR *)dest;
93 INTPTR *srci=(INTPTR *)src;
96 while(count>=sizeof(INTPTR)) {
99 count-=sizeof(INTPTR);
104 ((char *)dest)[off]=((char *)src)[off];
111 extern void * curr_heapbase;
112 extern void * curr_heapptr;
113 extern void * curr_heaptop;
116 /*** Global variables *****/
117 objlockstate_t *objlockscope;
120 * params: object header
121 * Increments the abort count for each object
123 void ABORTCOUNT(objheader_t * x) {
124 int avgTransSize = typesCausingAbort[TYPE(x)].numaccess / typesCausingAbort[TYPE(x)].numtrans;
125 float transAbortProbForObj = (PERCENT_ALLOWED_ABORT*FACTOR)/(float) avgTransSize;
126 float ObjAbortProb = x->abortCount/(float) (x->accessCount);
127 DEBUGSTM("ABORTSTATS: oid= %x, type= %2d, transAbortProb= %2.2f, ObjAbortProb= %2.2f, Typenumaccess= %3d, avgtranssize = %2d, ObjabortCount= %2d, ObjaccessCount= %3d\n", OID(x), TYPE(x), transAbortProbForObj, ObjAbortProb, typesCausingAbort[TYPE(x)].numaccess, avgTransSize, x->abortCount, x->accessCount);
128 /* Condition for locking objects */
129 if (((ObjAbortProb*100) >= transAbortProbForObj) && (x->riskyflag != 1)) {
130 DEBUGSTATS("AFTER LOCK ABORTSTATS: oid= %x, type= %2d, transAbortProb= %2.2f, ObjAbortProb= %2.2f, Typenumaccess= %3d, avgtranssize = %2d, ObjabortCount= %2d, ObjaccessCount= %3d\n", OID(x), TYPE(x), transAbortProbForObj, ObjAbortProb, typesCausingAbort[TYPE(x)].numaccess, avgTransSize, x->abortCount, x->accessCount);
131 //makes riskflag sticky
132 pthread_mutex_lock(&lockedobjstore);
133 if (objlockscope->offset<MAXOBJLIST) {
134 x->objlock=&(objlockscope->lock[objlockscope->offset++]);
136 objlockstate_t *tmp=malloc(sizeof(objlockstate_t));
137 tmp->next=objlockscope;
139 x->objlock=&(tmp->lock[0]);
142 pthread_mutex_unlock(&lockedobjstore);
143 pthread_mutex_init(x->objlock, NULL);
144 //should put a memory barrier here
150 /* ==================================================
152 * This function starts up the transaction runtime.
153 * ==================================================
159 /* =================================================
161 * This function initializes things required in the
163 * =================================================
166 //Transaction start is currently free...commit and aborting is not
168 c_ptrstack=&ptrstack;
169 c_primstack=&primstack;
170 c_branchstack=&branchstack;
174 /* =======================================================
176 * This function creates objects in the transaction record
177 * =======================================================
179 objheader_t *transCreateObj(void * ptr, unsigned int size) {
180 objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
181 objheader_t *retval=&tmp[1];
182 tmp->lock=RW_LOCK_BIAS;
184 //initialize obj lock to the header
186 // don't insert into table
187 if (newobjs->offset<MAXOBJLIST) {
188 newobjs->objs[newobjs->offset++]=retval;
190 struct objlist *tmp=malloc(sizeof(struct objlist));
196 return retval; //want space after object header
199 /* This functions inserts randowm wait delays in the order of msec
200 * Mostly used when transaction commits retry*/
201 void randomdelay(int softaborted) {
205 gettimeofday(&t,NULL);
208 req.tv_nsec = (long)((t.tv_usec)%(1<<softaborted))<<1; //1-11 microsec
209 nanosleep(&req, NULL);
213 /* =============================================================
215 * -finds the objects either in main heap
216 * -copies the object into the transaction cache
217 * =============================================================
219 //__attribute__ ((pure))
220 void *transRead(void * oid, void *gl) {
221 objheader_t *tmp, *objheader;
222 objheader_t *objcopy;
225 /* Read from the main heap */
227 objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
228 GETSIZE(size, header);
229 size += sizeof(objheader_t);
230 objcopy = (objheader_t *) objstrAlloc(size);
232 header->accessCount++;
233 if(header->riskyflag) {
234 header=needLock(header,gl);
237 A_memcpy(objcopy, header, size);
239 /* keep track of the object's access sequence in a transaction */
240 objheader_t *tmpheader = objcopy;
241 tmpheader->accessCount = ++t_objnumcount;
244 /* Insert into cache's lookup table */
246 if (((unsigned INTPTR)oid)<((unsigned INTPTR ) curr_heapbase)|| ((unsigned INTPTR)oid) >((unsigned INTPTR) curr_heapptr))
247 printf("ERROR! Bad object address!\n");
248 t_chashInsert(oid, &objcopy[1]);
253 struct objlist *ptr=newobjs;
254 while(ptr->next!=NULL) {
255 struct objlist *tmp=ptr->next;
264 void freelockedobjs() {
265 struct objlist *ptr=lockedobjs;
266 while(ptr->next!=NULL) {
267 struct objlist *tmp=ptr->next;
276 /* ================================================================
278 * - This function initiates the transaction commit process
279 * - goes through the transaction cache and decides
281 * ================================================================
284 int transCommit(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
296 /* Look through all the objects in the transaction hash table */
299 if (c_numelements<(c_size>>3))
300 finalResponse= alttraverseCache(commitmethod, primitives, locals, params);
302 finalResponse= traverseCache(commitmethod, primitives, locals, params);
304 if (c_numelements<(c_size>>3))
305 finalResponse= alttraverseCache();
307 finalResponse= traverseCache();
309 if(finalResponse == TRANS_ABORT) {
336 if(finalResponse == TRANS_COMMIT) {
361 /* wait a random amount of time before retrying to commit transaction*/
362 if(finalResponse == TRANS_SOFT_ABORT) {
372 //retry if too many soft aborts
390 //randomdelay(softaborted);
392 printf("Error: in %s() Unknown outcome", __func__);
399 You need to add free statements for oidrdage in a way that they will not appear if this option is not defined.
403 #define freearrays if (c_numelements>=200) { \
405 free(oidrdversion); \
407 if (t_numelements>=200) { \
411 #define freearrays if (c_numelements>=200) { \
413 free(oidrdversion); \
419 you need to set oidrdage in a way that does not appear if this macro is not defined.
423 #define allocarrays int t_numelements=c_numelements+dc_c_numelements; \
424 if (t_numelements<200) { \
425 oidwrlocked=wrlocked; \
427 oidwrlocked=malloc(t_numelements*sizeof(void *)); \
429 if (c_numelements<200) { \
430 oidrdlocked=rdlocked; \
431 oidrdversion=rdversion; \
433 int size=c_numelements*sizeof(void*); \
434 oidrdlocked=malloc(size); \
435 oidrdversion=malloc(size); \
438 #define allocarrays if (c_numelements<200) { \
439 oidrdlocked=rdlocked; \
440 oidrdversion=rdversion; \
441 oidwrlocked=wrlocked; \
443 int size=c_numelements*sizeof(void*); \
444 oidrdlocked=malloc(size); \
445 oidrdversion=malloc(size); \
446 oidwrlocked=malloc(size); \
453 /* ==================================================
455 * - goes through the transaction cache and
456 * - decides if a transaction should commit or abort
457 * ==================================================
460 int traverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
462 int traverseCache() {
464 /* Create info to keep track of objects that can be locked */
465 int numoidrdlocked=0;
466 int numoidwrlocked=0;
467 void * rdlocked[200];
469 void * wrlocked[200];
478 int objtypetraverse[TOTALNUMCLASSANDARRAY];
484 for(i=0; i<TOTALNUMCLASSANDARRAY; i++)
485 objtypetraverse[i] = 0;
488 chashlistnode_t *ptr = c_table;
489 /* Represents number of bins in the chash table */
490 unsigned int size = c_size;
491 for(i = 0; i<size; i++) {
492 chashlistnode_t *curr = &ptr[i];
493 /* Inner loop to traverse the linked list of the cache lookupTable */
494 while(curr != NULL) {
495 //if the first bin in hash table is empty
496 if(curr->key == NULL)
498 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1]; //cached object
499 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t)); //real object
500 unsigned int version = headeraddr->version;
502 if(STATUS(headeraddr) & DIRTY) {
503 /* Read from the main heap and compare versions */
504 if(write_trylock(&header->lock)) { //can aquire write lock
505 if (version == header->version) { /* versions match */
506 /* Keep track of objects locked */
507 oidwrlocked[numoidwrlocked++] = header;
509 oidwrlocked[numoidwrlocked++] = header;
510 transAbortProcess(oidwrlocked, numoidwrlocked);
512 header->abortCount++;
513 ObjSeqId = headeraddr->accessCount;
514 (typesCausingAbort[TYPE(header)]).numabort++;
515 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
516 (typesCausingAbort[TYPE(header)]).numtrans+=1;
517 objtypetraverse[TYPE(header)]=1;
518 getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
520 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
521 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
524 return TRANS_SOFT_ABORT;
529 if(version == header->version) {
533 transAbortProcess(oidwrlocked, numoidwrlocked);
535 header->abortCount++;
536 ObjSeqId = headeraddr->accessCount;
537 (typesCausingAbort[TYPE(header)]).numabort++;
538 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
539 (typesCausingAbort[TYPE(header)]).numtrans+=1;
540 objtypetraverse[TYPE(header)]=1;
541 //(typesCausingAbort[TYPE(header)])++;
543 #if defined(STMSTATS)||defined(SOFTABORT)
544 if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
547 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
548 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
551 return TRANS_SOFT_ABORT;
558 oidrdage[numoidrdlocked]=headeraddr->accessCount;
560 oidrdversion[numoidrdlocked]=version;
561 oidrdlocked[numoidrdlocked++]=header;
568 //acquire access set locks
569 unsigned int numoidwrtotal=numoidwrlocked;
571 chashlistnode_t *dc_curr = dc_c_list;
572 /* Inner loop to traverse the linked list of the cache lookupTable */
573 while(likely(dc_curr != NULL)) {
574 //if the first bin in hash table is empty
575 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
576 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
577 if(write_trylock(&header->lock)) { //can aquire write lock
578 oidwrlocked[numoidwrtotal++] = header;
580 //maybe we already have lock
581 void * key=dc_curr->key;
582 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
585 if(node->key == key) {
586 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
587 if(STATUS(headeraddr) & DIRTY) {
593 } while(node != NULL);
595 //have to abort to avoid deadlock
596 transAbortProcess(oidwrlocked, numoidwrtotal);
598 ObjSeqId = headeraddr->accessCount;
599 header->abortCount++;
600 (typesCausingAbort[TYPE(header)]).numabort++;
601 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
602 (typesCausingAbort[TYPE(header)]).numtrans+=1;
603 objtypetraverse[TYPE(header)]=1;
605 #if defined(STMSTATS)||defined(SOFTABORT)
606 if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
609 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
610 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
613 return TRANS_SOFT_ABORT;
618 dc_curr = dc_curr->lnext;
622 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
624 for(i=0; i<numoidrdlocked; i++) {
625 /* Read from the main heap and compare versions */
626 objheader_t *header=oidrdlocked[i];
627 unsigned int version=oidrdversion[i];
628 if(header->lock>0) { //not write locked
630 if(version != header->version) { /* versions do not match */
632 transAbortProcess(oidwrlocked, numoidwrtotal);
634 transAbortProcess(oidwrlocked, numoidwrlocked);
637 ObjSeqId = oidrdage[i];
638 header->abortCount++;
639 (typesCausingAbort[TYPE(header)]).numabort++;
640 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
641 (typesCausingAbort[TYPE(header)]).numtrans+=1;
642 objtypetraverse[TYPE(header)]=1;
643 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
645 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
646 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
651 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
652 //couldn't get lock because we already have it
653 //check if it is the right version number
654 if (version!=header->version) {
655 transAbortProcess(oidwrlocked, numoidwrtotal);
657 ObjSeqId = oidrdage[i];
658 header->abortCount++;
659 (typesCausingAbort[TYPE(header)]).numabort++;
660 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
661 (typesCausingAbort[TYPE(header)]).numtrans+=1;
662 objtypetraverse[TYPE(header)]=1;
663 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
665 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u, oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
666 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
671 } else { /* cannot aquire lock */
672 //do increment as we didn't get lock
673 if(version == header->version) {
677 transAbortProcess(oidwrlocked, numoidwrtotal);
679 transAbortProcess(oidwrlocked, numoidwrlocked);
682 ObjSeqId = oidrdage[i];
683 header->abortCount++;
684 (typesCausingAbort[TYPE(header)]).numabort++;
685 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
686 (typesCausingAbort[TYPE(header)]).numtrans+=1;
687 objtypetraverse[TYPE(header)]=1;
689 #if defined(STMSTATS)||defined(SOFTABORT)
690 if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
693 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
694 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
697 return TRANS_SOFT_ABORT;
704 //need to validate auxilary readset
705 rdchashlistnode_t *rd_curr = rd_c_list;
706 /* Inner loop to traverse the linked list of the cache lookupTable */
707 while(likely(rd_curr != NULL)) {
708 //if the first bin in hash table is empty
709 unsigned int version=rd_curr->version;
710 objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
711 if(header->lock>0) { //object is not locked
712 if (version!=header->version) {
715 transAbortProcess(oidwrlocked, numoidwrtotal);
717 transAbortProcess(oidwrlocked, numoidwrlocked);
720 //ABORTCOUNT(header);
721 (typesCausingAbort[TYPE(header)])++;
723 #if defined(STMSTATS)||defined(SOFTABORT)
724 //if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
727 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
728 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
731 return TRANS_SOFT_ABORT;
736 //maybe we already have lock
737 if (version==header->version) {
738 void * key=rd_curr->key;
740 //check to see if it is in the delaycomp table
742 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
747 } while(node != NULL);
752 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
754 if(node->key == key) {
755 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
756 if(STATUS(headeraddr) & DIRTY) {
761 } while(node != NULL);
765 //have to abort to avoid deadlock
766 transAbortProcess(oidwrlocked, numoidwrtotal);
768 transAbortProcess(oidwrlocked, numoidwrlocked);
772 //ABORTCOUNT(header);
773 (typesCausingAbort[TYPE(header)])++;
775 #if defined(STMSTATS)||defined(SOFTABORT)
776 //if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
779 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
780 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
783 return TRANS_SOFT_ABORT;
788 rd_curr = rd_curr->lnext;
792 /* Decide the final response */
794 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
796 transCommitProcess(oidwrlocked, numoidwrlocked);
798 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
803 /* ==================================================
805 * - goes through the transaction cache and
806 * - decides if a transaction should commit or abort
807 * ==================================================
811 int alttraverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
813 int alttraverseCache() {
815 /* Create info to keep track of objects that can be locked */
816 int numoidrdlocked=0;
817 int numoidwrlocked=0;
818 void * rdlocked[200];
820 void * wrlocked[200];
829 int objtypetraverse[TOTALNUMCLASSANDARRAY];
835 for(i=0; i<TOTALNUMCLASSANDARRAY; i++)
836 objtypetraverse[i] = 0;
838 chashlistnode_t *curr = c_list;
839 /* Inner loop to traverse the linked list of the cache lookupTable */
840 while(likely(curr != NULL)) {
841 //if the first bin in hash table is empty
842 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
843 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
844 unsigned int version = headeraddr->version;
846 if(STATUS(headeraddr) & DIRTY) {
847 /* Read from the main heap and compare versions */
848 if(likely(write_trylock(&header->lock))) { //can aquire write lock
849 if (likely(version == header->version)) { /* versions match */
850 /* Keep track of objects locked */
851 oidwrlocked[numoidwrlocked++] = header;
853 oidwrlocked[numoidwrlocked++] = header;
854 transAbortProcess(oidwrlocked, numoidwrlocked);
856 header->abortCount++;
857 ObjSeqId = headeraddr->accessCount;
858 (typesCausingAbort[TYPE(header)]).numabort++;
859 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
860 (typesCausingAbort[TYPE(header)]).numtrans+=1;
861 objtypetraverse[TYPE(header)]=1;
862 getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
864 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
865 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
869 } else { /* cannot aquire lock */
870 if(version == header->version) {
874 transAbortProcess(oidwrlocked, numoidwrlocked);
876 header->abortCount++;
877 ObjSeqId = headeraddr->accessCount;
878 (typesCausingAbort[TYPE(header)]).numabort++;
879 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
880 (typesCausingAbort[TYPE(header)]).numtrans+=1;
881 objtypetraverse[TYPE(header)]=1;
883 #if defined(STMSTATS)||defined(SOFTABORT)
884 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
887 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
888 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
891 return TRANS_SOFT_ABORT;
896 /* Read from the main heap and compare versions */
897 oidrdversion[numoidrdlocked]=version;
898 oidrdlocked[numoidrdlocked++] = header;
904 //acquire other locks
905 unsigned int numoidwrtotal=numoidwrlocked;
906 chashlistnode_t *dc_curr = dc_c_list;
907 /* Inner loop to traverse the linked list of the cache lookupTable */
908 while(likely(dc_curr != NULL)) {
909 //if the first bin in hash table is empty
910 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
911 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
912 if(write_trylock(&header->lock)) { //can aquire write lock
913 oidwrlocked[numoidwrtotal++] = header;
915 //maybe we already have lock
916 void * key=dc_curr->key;
917 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
920 if(node->key == key) {
921 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
922 if(STATUS(headeraddr) & DIRTY) {
927 } while(node != NULL);
929 //have to abort to avoid deadlock
930 transAbortProcess(oidwrlocked, numoidwrtotal);
932 header->abortCount++;
933 ObjSeqId = headeraddr->accessCount;
934 (typesCausingAbort[TYPE(header)]).numabort++;
935 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
936 (typesCausingAbort[TYPE(header)]).numtrans+=1;
937 objtypetraverse[TYPE(header)]=1;
939 #if defined(STMSTATS)||defined(SOFTABORT)
940 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
943 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
944 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
947 return TRANS_SOFT_ABORT;
952 dc_curr = dc_curr->lnext;
956 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
958 for(i=0; i<numoidrdlocked; i++) {
959 objheader_t * header=oidrdlocked[i];
960 unsigned int version=oidrdversion[i];
963 if(version != header->version) {
965 transAbortProcess(oidwrlocked, numoidwrtotal);
967 transAbortProcess(oidwrlocked, numoidwrlocked);
970 ObjSeqId = oidrdage[i];
971 header->abortCount++;
972 (typesCausingAbort[TYPE(header)]).numabort++;
973 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
974 (typesCausingAbort[TYPE(header)]).numtrans+=1;
975 objtypetraverse[TYPE(header)]=1;
976 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
978 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
979 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
984 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
985 //couldn't get lock because we already have it
986 //check if it is the right version number
987 if (version!=header->version) {
988 transAbortProcess(oidwrlocked, numoidwrtotal);
990 ObjSeqId = oidrdage[i];
991 header->abortCount++;
992 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
994 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u oid: %x\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version, OID(header));
995 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1000 } else { /* cannot aquire lock */
1001 if(version == header->version) {
1005 transAbortProcess(oidwrlocked, numoidwrtotal);
1007 transAbortProcess(oidwrlocked, numoidwrlocked);
1010 ObjSeqId = oidrdage[i];
1011 header->abortCount++;
1012 (typesCausingAbort[TYPE(header)]).numabort++;
1013 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
1014 (typesCausingAbort[TYPE(header)]).numtrans+=1;
1015 objtypetraverse[TYPE(header)]=1;
1017 #if defined(STMSTATS)||defined(SOFTABORT)
1018 if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse))
1021 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1022 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1025 return TRANS_SOFT_ABORT;
1032 //need to validate auxilary readset
1033 rdchashlistnode_t *rd_curr = rd_c_list;
1034 /* Inner loop to traverse the linked list of the cache lookupTable */
1035 while(likely(rd_curr != NULL)) {
1036 //if the first bin in hash table is empty
1037 int version=rd_curr->version;
1038 objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
1039 if(header->lock>0) { //object is not locked
1040 if (version!=header->version) {
1043 transAbortProcess(oidwrlocked, numoidwrtotal);
1045 transAbortProcess(oidwrlocked, numoidwrlocked);
1048 //ABORTCOUNT(header);
1049 (typesCausingAbort[TYPE(header)])++;
1051 #if defined(STMSTATS)||defined(SOFTABORT)
1052 //if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
1055 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1056 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1059 return TRANS_SOFT_ABORT;
1064 if (version==header->version) {
1065 void * key=rd_curr->key;
1067 //check to see if it is in the delaycomp table
1069 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
1071 if(node->key == key)
1074 } while(node != NULL);
1077 //check normal table
1079 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
1081 if(node->key == key) {
1082 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
1083 if(STATUS(headeraddr) & DIRTY) {
1088 } while(node != NULL);
1092 //have to abort to avoid deadlock
1093 transAbortProcess(oidwrlocked, numoidwrtotal);
1095 transAbortProcess(oidwrlocked, numoidwrlocked);
1098 //ABORTCOUNT(header);
1099 (typesCausingAbort[TYPE(header)])++;
1101 #if defined(STMSTATS)||defined(SOFTABORT)
1102 // if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
1105 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1106 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1109 return TRANS_SOFT_ABORT;
1114 rd_curr = rd_curr->lnext;
1118 /* Decide the final response */
1120 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
1122 transCommitProcess(oidwrlocked, numoidwrlocked);
1124 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
1126 return TRANS_COMMIT;
1129 /* ==================================
1132 * =================================
1134 void transAbortProcess(void **oidwrlocked, int numoidwrlocked) {
1136 objheader_t *header;
1137 /* Release read locks */
1139 /* Release write locks */
1140 for(i=numoidwrlocked-1; i>=0; i--) {
1141 /* Read from the main heap */
1142 header = (objheader_t *)oidwrlocked[i];
1143 write_unlock(&header->lock);
1147 /* clear trec and then release objects locked */
1148 struct objlist *ptr=lockedobjs;
1150 int max=ptr->offset;
1151 for(i=max-1; i>=0; i--) {
1152 header = (objheader_t *)ptr->objs[i];
1153 header->trec = NULL;
1154 pthread_mutex_unlock(header->objlock);
1161 /* ==================================
1162 * transCommitProcess
1164 * =================================
1167 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked, int numoidwrtotal, void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
1169 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked) {
1171 objheader_t *header;
1174 struct objlist *ptr=newobjs;
1176 int max=ptr->offset;
1177 for(i=0; i<max; i++) {
1178 //clear the new flag
1179 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
1184 /* Copy from transaction cache -> main object store */
1185 for (i = numoidwrlocked-1; i >=0; i--) {
1186 /* Read from the main heap */
1187 header = (objheader_t *)oidwrlocked[i];
1189 GETSIZE(tmpsize, header);
1190 struct ___Object___ *dst=(struct ___Object___*)(((char *)oidwrlocked[i])+sizeof(objheader_t));
1191 struct ___Object___ *src=t_chashSearch(dst);
1192 dst->___cachedCode___=src->___cachedCode___;
1193 dst->___cachedHash___=src->___cachedHash___;
1194 A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
1199 // call commit method
1202 branchstack.count=0;
1203 commitmethod(params, locals, primitives);
1206 /* Release write locks */
1208 for(i=numoidwrtotal-1; i>=0; i--) {
1210 for(i=numoidwrlocked-1; i>=0; i--) {
1212 header = (objheader_t *)oidwrlocked[i];
1214 write_unlock(&header->lock);
1218 /* clear trec and then release objects locked */
1221 int max=ptr->offset;
1222 for(i=max-1; i>=0; i--) {
1223 header = (objheader_t *)ptr->objs[i];
1224 header->trec = NULL;
1225 pthread_mutex_unlock(header->objlock);