1 /* ============================================================
3 * - single thread commit on local machine
4 * =============================================================
5 * Copyright (c) 2009, University of California, Irvine, USA.
9 * =============================================================
16 /* Per thread transaction variables */
17 __thread objstr_t *t_cache;
18 __thread objstr_t *t_reserve;
19 __thread struct objlist * newobjs;
22 #include "delaycomp.h"
23 __thread struct pointerlist ptrstack;
24 __thread struct primitivelist primstack;
25 __thread struct branchlist branchstack;
26 struct pointerlist *c_ptrstack;
27 struct primitivelist *c_primstack;
28 struct branchlist *c_branchstack;
32 int numTransCommit = 0;
33 int numTransAbort = 0;
35 int nSoftAbortCommit = 0;
36 int nSoftAbortAbort = 0;
40 /* Thread variable for locking/unlocking */
41 __thread threadrec_t *trec;
42 __thread struct objlist * lockedobjs;
44 int typesCausingAbort[TOTALNUMCLASSANDARRAY];
45 /******Keep track of objects and types causing aborts******/
46 /* TODO uncomment for later use
47 #define DEBUGSTMSTAT(args...) { \
52 #define DEBUGSTMSTAT(args...)
54 #define DEBUGSTMSTAT(args...)
58 #define DEBUGSTM(x...) printf(x);
60 #define DEBUGSTM(x...)
64 void * A_memcpy (void * dest, const void * src, size_t count);
66 #define A_memcpy memcpy
69 extern void * curr_heapbase;
70 extern void * curr_heapptr;
71 extern void * curr_heaptop;
74 /*** Global variables *****/
75 objlockstate_t *objlockscope;
78 * params: object header
79 * Increments the abort count for each object
81 void ABORTCOUNT(objheader_t * x) {
83 if (x->abortCount > MAXABORTS && (x->riskyflag != 1)) {
84 //makes riskflag sticky
85 pthread_mutex_lock(&lockedobjstore);
86 if (objlockscope->offset<MAXOBJLIST) {
87 x->objlock=&(objlockscope->lock[objlockscope->offset++]);
89 objlockstate_t *tmp=malloc(sizeof(objlockstate_t));
90 tmp->next=objlockscope;
92 x->objlock=&(tmp->lock[0]);
95 pthread_mutex_unlock(&lockedobjstore);
96 pthread_mutex_init(x->objlock, NULL);
97 //should put a memory barrier here
103 /* ==================================================
105 * This function starts up the transaction runtime.
106 * ==================================================
112 /* ======================================
114 * - create an object store of given size
115 * ======================================
117 objstr_t *objstrCreate(unsigned int size) {
119 if((tmp = calloc(1, (sizeof(objstr_t) + size))) == NULL) {
120 printf("%s() Calloc error at line %d, %s\n", __func__, __LINE__, __FILE__);
125 tmp->top = tmp + 1; //points to end of objstr_t structure!
130 while(t_cache->next!=NULL) {
131 objstr_t *next=t_cache->next;
132 t_cache->next=t_reserve;
136 t_cache->top=t_cache+1;
139 //free entire list, starting at store
140 void objstrDelete(objstr_t *store) {
142 while (store != NULL) {
150 /* =================================================
152 * This function initializes things required in the
154 * =================================================
157 //Transaction start is currently free...commit and aborting is not
159 c_ptrstack=&ptrstack;
160 c_primstack=&primstack;
161 c_branchstack=&branchstack;
165 /* =======================================================
167 * This function creates objects in the transaction record
168 * =======================================================
170 objheader_t *transCreateObj(void * ptr, unsigned int size) {
171 objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
172 objheader_t *retval=&tmp[1];
173 tmp->lock=RW_LOCK_BIAS;
175 //initialize obj lock to the header
177 // don't insert into table
178 if (newobjs->offset<MAXOBJLIST) {
179 newobjs->objs[newobjs->offset++]=retval;
181 struct objlist *tmp=malloc(sizeof(struct objlist));
187 return retval; //want space after object header
190 /* This functions inserts randowm wait delays in the order of msec
191 * Mostly used when transaction commits retry*/
192 void randomdelay(int softaborted) {
196 gettimeofday(&t,NULL);
199 req.tv_nsec = (long)((t.tv_usec)%(1<<softaborted))<<1; //1-11 microsec
200 nanosleep(&req, NULL);
204 /* ==============================================
206 * - allocate space in an object store
207 * ==============================================
209 void *objstrAlloc(unsigned int size) {
212 objstr_t *store=t_cache;
218 if (OSFREE(store)>=size) {
223 if ((store=store->next)==NULL)
228 unsigned int newsize=size>DEFAULT_OBJ_STORE_SIZE ? size : DEFAULT_OBJ_STORE_SIZE;
229 objstr_t **otmp=&t_reserve;
231 while((ptr=*otmp)!=NULL) {
232 if (ptr->size>=newsize) {
237 ptr->top=((char *)(&ptr[1]))+size;
242 objstr_t *os=(objstr_t *)calloc(1,(sizeof(objstr_t) + newsize));
247 os->top=((char *)nptr)+size;
253 /* =============================================================
255 * -finds the objects either in main heap
256 * -copies the object into the transaction cache
257 * =============================================================
259 __attribute__ ((pure)) void *transRead(void * oid, void *gl) {
260 objheader_t *tmp, *objheader;
261 objheader_t *objcopy;
264 /* Read from the main heap */
266 objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
267 GETSIZE(size, header);
268 size += sizeof(objheader_t);
269 objcopy = (objheader_t *) objstrAlloc(size);
271 header->accessCount++;
272 if(header->riskyflag) {
273 header=needLock(header,gl);
276 A_memcpy(objcopy, header, size);
277 /* Insert into cache's lookup table */
279 if (((unsigned INTPTR)oid)<((unsigned INTPTR ) curr_heapbase)|| ((unsigned INTPTR)oid) >((unsigned INTPTR) curr_heapptr))
280 printf("ERROR! Bad object address!\n");
281 t_chashInsert(oid, &objcopy[1]);
286 struct objlist *ptr=newobjs;
287 while(ptr->next!=NULL) {
288 struct objlist *tmp=ptr->next;
297 void freelockedobjs() {
298 struct objlist *ptr=lockedobjs;
299 while(ptr->next!=NULL) {
300 struct objlist *tmp=ptr->next;
309 /* ================================================================
311 * - This function initiates the transaction commit process
312 * - goes through the transaction cache and decides
314 * ================================================================
317 int transCommit(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
323 /* Look through all the objects in the transaction hash table */
326 if (c_numelements<(c_size>>3))
327 finalResponse= alttraverseCache(commitmethod, primitives, locals, params);
329 finalResponse= traverseCache(commitmethod, primitives, locals, params);
331 if (c_numelements<(c_size>>3))
332 finalResponse= alttraverseCache();
334 finalResponse= traverseCache();
336 if(finalResponse == TRANS_ABORT) {
360 if(finalResponse == TRANS_COMMIT) {
385 /* wait a random amount of time before retrying to commit transaction*/
386 if(finalResponse == TRANS_SOFT_ABORT) {
396 //retry if too many soft aborts
414 //randomdelay(softaborted);
416 printf("Error: in %s() Unknown outcome", __func__);
423 #define freearrays if (c_numelements>=200) { \
425 free(oidrdversion); \
427 if (t_numelements>=200) { \
431 #define freearrays if (c_numelements>=200) { \
433 free(oidrdversion); \
439 #define allocarrays int t_numelements=c_numelements+dc_c_numelements; \
440 if (t_numelements<200) { \
441 oidwrlocked=wrlocked; \
443 oidwrlocked=malloc(t_numelements*sizeof(void *)); \
445 if (c_numelements<200) { \
446 oidrdlocked=rdlocked; \
447 oidrdversion=rdversion; \
449 int size=c_numelements*sizeof(void*); \
450 oidrdlocked=malloc(size); \
451 oidrdversion=malloc(size); \
454 #define allocarrays if (c_numelements<200) { \
455 oidrdlocked=rdlocked; \
456 oidrdversion=rdversion; \
457 oidwrlocked=wrlocked; \
459 int size=c_numelements*sizeof(void*); \
460 oidrdlocked=malloc(size); \
461 oidrdversion=malloc(size); \
462 oidwrlocked=malloc(size); \
469 /* ==================================================
471 * - goes through the transaction cache and
472 * - decides if a transaction should commit or abort
473 * ==================================================
476 int traverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
478 int traverseCache() {
480 /* Create info to keep track of objects that can be locked */
481 int numoidrdlocked=0;
482 int numoidwrlocked=0;
483 void * rdlocked[200];
485 void * wrlocked[200];
493 chashlistnode_t *ptr = c_table;
494 /* Represents number of bins in the chash table */
495 unsigned int size = c_size;
496 for(i = 0; i<size; i++) {
497 chashlistnode_t *curr = &ptr[i];
498 /* Inner loop to traverse the linked list of the cache lookupTable */
499 while(curr != NULL) {
500 //if the first bin in hash table is empty
501 if(curr->key == NULL)
503 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
504 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
505 unsigned int version = headeraddr->version;
507 if(STATUS(headeraddr) & DIRTY) {
508 /* Read from the main heap and compare versions */
509 if(write_trylock(&header->lock)) { //can aquire write lock
510 if (version == header->version) { /* versions match */
511 /* Keep track of objects locked */
512 oidwrlocked[numoidwrlocked++] = header;
514 oidwrlocked[numoidwrlocked++] = header;
515 transAbortProcess(oidwrlocked, numoidwrlocked);
518 (typesCausingAbort[TYPE(header)])++;
519 getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion);
521 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
522 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
525 return TRANS_SOFT_ABORT;
530 if(version == header->version) {
534 transAbortProcess(oidwrlocked, numoidwrlocked);
537 (typesCausingAbort[TYPE(header)])++;
539 #if defined(STMSTATS)||defined(SOFTABORT)
540 if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion))
543 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
544 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
547 return TRANS_SOFT_ABORT;
553 oidrdversion[numoidrdlocked]=version;
554 oidrdlocked[numoidrdlocked++] = header;
561 //acquire access set locks
562 unsigned int numoidwrtotal=numoidwrlocked;
564 chashlistnode_t *dc_curr = dc_c_list;
565 /* Inner loop to traverse the linked list of the cache lookupTable */
566 while(likely(dc_curr != NULL)) {
567 //if the first bin in hash table is empty
568 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
569 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
570 if(write_trylock(&header->lock)) { //can aquire write lock
571 oidwrlocked[numoidwrtotal++] = header;
573 //maybe we already have lock
574 void * key=dc_curr->key;
575 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
578 if(node->key == key) {
579 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
580 if(STATUS(headeraddr) & DIRTY) {
586 } while(node != NULL);
588 //have to abort to avoid deadlock
589 transAbortProcess(oidwrlocked, numoidwrtotal);
592 (typesCausingAbort[TYPE(header)])++;
594 #if defined(STMSTATS)||defined(SOFTABORT)
595 if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion))
598 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
599 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
602 return TRANS_SOFT_ABORT;
607 dc_curr = dc_curr->lnext;
611 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
613 for(i=0; i<numoidrdlocked; i++) {
614 /* Read from the main heap and compare versions */
615 objheader_t *header=oidrdlocked[i];
616 unsigned int version=oidrdversion[i];
617 if(header->lock>0) { //not write locked
618 if(version != header->version) { /* versions do not match */
620 transAbortProcess(oidwrlocked, numoidwrtotal);
622 transAbortProcess(oidwrlocked, numoidwrlocked);
626 (typesCausingAbort[TYPE(header)])++;
627 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
629 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
630 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
635 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
636 //couldn't get lock because we already have it
637 //check if it is the right version number
638 if (version!=header->version) {
639 transAbortProcess(oidwrlocked, numoidwrtotal);
642 (typesCausingAbort[TYPE(header)])++;
643 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
645 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
646 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
651 } else { /* cannot aquire lock */
652 //do increment as we didn't get lock
653 if(version == header->version) {
657 transAbortProcess(oidwrlocked, numoidwrtotal);
659 transAbortProcess(oidwrlocked, numoidwrlocked);
663 (typesCausingAbort[TYPE(header)])++;
665 #if defined(STMSTATS)||defined(SOFTABORT)
666 if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion))
669 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
670 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
673 return TRANS_SOFT_ABORT;
680 //need to validate auxilary readset
681 rdchashlistnode_t *rd_curr = rd_c_list;
682 /* Inner loop to traverse the linked list of the cache lookupTable */
683 while(likely(rd_curr != NULL)) {
684 //if the first bin in hash table is empty
685 unsigned int version=rd_curr->version;
686 objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
687 if(header->lock>0) { //object is not locked
688 if (version!=header->version) {
691 transAbortProcess(oidwrlocked, numoidwrtotal);
693 transAbortProcess(oidwrlocked, numoidwrlocked);
697 (typesCausingAbort[TYPE(header)])++;
699 #if defined(STMSTATS)||defined(SOFTABORT)
700 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
703 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
704 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
707 return TRANS_SOFT_ABORT;
712 //maybe we already have lock
713 if (version==header->version) {
714 void * key=rd_curr->key;
716 //check to see if it is in the delaycomp table
718 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
723 } while(node != NULL);
728 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
730 if(node->key == key) {
731 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
732 if(STATUS(headeraddr) & DIRTY) {
737 } while(node != NULL);
741 //have to abort to avoid deadlock
742 transAbortProcess(oidwrlocked, numoidwrtotal);
744 transAbortProcess(oidwrlocked, numoidwrlocked);
749 (typesCausingAbort[TYPE(header)])++;
751 #if defined(STMSTATS)||defined(SOFTABORT)
752 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
755 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
756 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
759 return TRANS_SOFT_ABORT;
764 rd_curr = rd_curr->lnext;
768 /* Decide the final response */
770 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
772 transCommitProcess(oidwrlocked, numoidwrlocked);
774 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
779 /* ==================================================
781 * - goes through the transaction cache and
782 * - decides if a transaction should commit or abort
783 * ==================================================
787 int alttraverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
789 int alttraverseCache() {
791 /* Create info to keep track of objects that can be locked */
792 int numoidrdlocked=0;
793 int numoidwrlocked=0;
794 void * rdlocked[200];
796 void * wrlocked[200];
804 chashlistnode_t *curr = c_list;
805 /* Inner loop to traverse the linked list of the cache lookupTable */
806 while(likely(curr != NULL)) {
807 //if the first bin in hash table is empty
808 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
809 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
810 unsigned int version = headeraddr->version;
812 if(STATUS(headeraddr) & DIRTY) {
813 /* Read from the main heap and compare versions */
814 if(likely(write_trylock(&header->lock))) { //can aquire write lock
815 if (likely(version == header->version)) { /* versions match */
816 /* Keep track of objects locked */
817 oidwrlocked[numoidwrlocked++] = header;
819 oidwrlocked[numoidwrlocked++] = header;
820 transAbortProcess(oidwrlocked, numoidwrlocked);
823 (typesCausingAbort[TYPE(header)])++;
824 getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion);
826 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
827 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
831 } else { /* cannot aquire lock */
832 if(version == header->version) {
836 transAbortProcess(oidwrlocked, numoidwrlocked);
839 (typesCausingAbort[TYPE(header)])++;
841 #if defined(STMSTATS)||defined(SOFTABORT)
842 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
845 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
846 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
849 return TRANS_SOFT_ABORT;
854 /* Read from the main heap and compare versions */
855 oidrdversion[numoidrdlocked]=version;
856 oidrdlocked[numoidrdlocked++] = header;
862 //acquire other locks
863 unsigned int numoidwrtotal=numoidwrlocked;
864 chashlistnode_t *dc_curr = dc_c_list;
865 /* Inner loop to traverse the linked list of the cache lookupTable */
866 while(likely(dc_curr != NULL)) {
867 //if the first bin in hash table is empty
868 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
869 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
870 if(write_trylock(&header->lock)) { //can aquire write lock
871 oidwrlocked[numoidwrtotal++] = header;
873 //maybe we already have lock
874 void * key=dc_curr->key;
875 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
878 if(node->key == key) {
879 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
880 if(STATUS(headeraddr) & DIRTY) {
885 } while(node != NULL);
887 //have to abort to avoid deadlock
888 transAbortProcess(oidwrlocked, numoidwrtotal);
891 (typesCausingAbort[TYPE(header)])++;
893 #if defined(STMSTATS)||defined(SOFTABORT)
894 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
897 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
898 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
901 return TRANS_SOFT_ABORT;
906 dc_curr = dc_curr->lnext;
910 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
912 for(i=0; i<numoidrdlocked; i++) {
913 objheader_t * header=oidrdlocked[i];
914 unsigned int version=oidrdversion[i];
915 if(header->lock>=0) {
916 if(version != header->version) {
918 transAbortProcess(oidwrlocked, numoidwrtotal);
920 transAbortProcess(oidwrlocked, numoidwrlocked);
924 (typesCausingAbort[TYPE(header)])++;
925 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
927 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
928 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
933 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
934 //couldn't get lock because we already have it
935 //check if it is the right version number
936 if (version!=header->version) {
937 transAbortProcess(oidwrlocked, numoidwrtotal);
940 (typesCausingAbort[TYPE(header)])++;
941 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
943 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
944 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
949 } else { /* cannot aquire lock */
950 if(version == header->version) {
954 transAbortProcess(oidwrlocked, numoidwrtotal);
956 transAbortProcess(oidwrlocked, numoidwrlocked);
960 (typesCausingAbort[TYPE(header)])++;
962 #if defined(STMSTATS)||defined(SOFTABORT)
963 if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion))
966 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
967 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
970 return TRANS_SOFT_ABORT;
977 //need to validate auxilary readset
978 rdchashlistnode_t *rd_curr = rd_c_list;
979 /* Inner loop to traverse the linked list of the cache lookupTable */
980 while(likely(rd_curr != NULL)) {
981 //if the first bin in hash table is empty
982 int version=rd_curr->version;
983 objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
984 if(header->lock>0) { //object is not locked
985 if (version!=header->version) {
988 transAbortProcess(oidwrlocked, numoidwrtotal);
990 transAbortProcess(oidwrlocked, numoidwrlocked);
994 (typesCausingAbort[TYPE(header)])++;
996 #if defined(STMSTATS)||defined(SOFTABORT)
997 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
1000 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1001 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1004 return TRANS_SOFT_ABORT;
1009 if (version==header->version) {
1010 void * key=rd_curr->key;
1012 //check to see if it is in the delaycomp table
1014 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
1016 if(node->key == key)
1019 } while(node != NULL);
1022 //check normal table
1024 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
1026 if(node->key == key) {
1027 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
1028 if(STATUS(headeraddr) & DIRTY) {
1033 } while(node != NULL);
1037 //have to abort to avoid deadlock
1038 transAbortProcess(oidwrlocked, numoidwrtotal);
1040 transAbortProcess(oidwrlocked, numoidwrlocked);
1044 (typesCausingAbort[TYPE(header)])++;
1046 #if defined(STMSTATS)||defined(SOFTABORT)
1047 if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
1050 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1051 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1054 return TRANS_SOFT_ABORT;
1059 rd_curr = rd_curr->lnext;
1063 /* Decide the final response */
1065 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
1067 transCommitProcess(oidwrlocked, numoidwrlocked);
1069 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
1071 return TRANS_COMMIT;
1074 /* ==================================
1077 * =================================
1079 void transAbortProcess(void **oidwrlocked, int numoidwrlocked) {
1081 objheader_t *header;
1082 /* Release read locks */
1084 /* Release write locks */
1085 for(i=numoidwrlocked-1; i>=0; i--) {
1086 /* Read from the main heap */
1087 header = (objheader_t *)oidwrlocked[i];
1088 write_unlock(&header->lock);
1092 /* clear trec and then release objects locked */
1093 struct objlist *ptr=lockedobjs;
1095 int max=ptr->offset;
1096 for(i=max-1; i>=0; i--) {
1097 header = (objheader_t *)ptr->objs[i];
1098 header->trec = NULL;
1099 pthread_mutex_unlock(header->objlock);
1106 /* ==================================
1107 * transCommitProcess
1109 * =================================
1112 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked, int numoidwrtotal, void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
1114 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked) {
1116 objheader_t *header;
1119 struct objlist *ptr=newobjs;
1121 int max=ptr->offset;
1122 for(i=0; i<max; i++) {
1123 //clear the new flag
1124 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
1129 /* Copy from transaction cache -> main object store */
1130 for (i = numoidwrlocked-1; i >=0; i--) {
1131 /* Read from the main heap */
1132 header = (objheader_t *)oidwrlocked[i];
1134 GETSIZE(tmpsize, header);
1135 struct ___Object___ *dst=(struct ___Object___*)(((char *)oidwrlocked[i])+sizeof(objheader_t));
1136 struct ___Object___ *src=t_chashSearch(dst);
1137 dst->___cachedCode___=src->___cachedCode___;
1138 dst->___cachedHash___=src->___cachedHash___;
1139 A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
1140 __asm__ __volatile__("": : :"memory");
1145 __asm__ __volatile__("": : :"memory");
1148 // call commit method
1151 branchstack.count=0;
1152 commitmethod(params, locals, primitives);
1155 /* Release write locks */
1157 for(i=numoidwrtotal-1; i>=0; i--) {
1159 for(i=numoidwrlocked-1; i>=0; i--) {
1161 header = (objheader_t *)oidwrlocked[i];
1165 write_unlock(&header->lock);
1169 /* clear trec and then release objects locked */
1172 int max=ptr->offset;
1173 for(i=max-1; i>=0; i--) {
1174 header = (objheader_t *)ptr->objs[i];
1175 header->trec = NULL;
1176 pthread_mutex_unlock(header->objlock);
1183 #if defined(STMSTATS)||defined(SOFTABORT)
1184 /** ========================================================================================
1185 * getTotalAbortCount (for traverseCache only)
1186 * params : start: start index of the loop
1187 * : stop: stop index of the loop
1188 * : startptr: pointer that points to where to start looking in the cache hash table
1189 * : numoidrdlocked : number of objects read that are locked
1190 * : oidrdlocked : array of objects read and currently locked
1191 * : oidrdversion : array of versions of object read
1192 * =========================================================================================
1194 int getTotalAbortCount(int start, int stop, void *startptr, int numoidrdlocked, void *oidrdlocked, int *oidrdversion) {
1198 chashlistnode_t *curr = (chashlistnode_t *) startptr;
1199 chashlistnode_t *ptr = c_table;
1200 /* First go through all objects left in the cache that have not been covered yet */
1201 for(i = start; i < stop; i++) {
1204 /* Inner loop to traverse the linked list of the cache lookupTable */
1205 while(curr != NULL) {
1206 if(curr->key == NULL)
1208 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
1209 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
1210 unsigned int version = headeraddr->version;
1211 /* versions do not match */
1212 if(version != header->version) {
1215 (typesCausingAbort[TYPE(header)])++;
1224 /* Then go through all objects that are read and are currently present in the readLockedArray */
1225 if(numoidrdlocked>0) {
1226 for(i=0; i<numoidrdlocked; i++) {
1227 objheader_t *header = ((void **)oidrdlocked)[i];
1228 unsigned int version = oidrdversion[i];
1229 if(version != header->version) { /* versions do not match */
1232 (typesCausingAbort[TYPE(header)])++;
1242 /** ========================================================================================
1243 * getTotalAbortCount2 (for alttraverseCache only)
1244 * params : startptr: pointer that points to where to start looking in the cache hash table
1245 * : numoidrdlocked : number of objects read that are locked
1246 * : oidrdlocked : array of objects read and currently locked
1247 * : oidrdversion : array of versions of object read
1248 * =========================================================================================
1250 int getTotalAbortCount2(void *startptr, int numoidrdlocked, void *oidrdlocked, int *oidrdversion) {
1252 chashlistnode_t *curr = (chashlistnode_t *) startptr;
1253 /* Inner loop to traverse the linked list of the cache lookupTable */
1254 while(curr != NULL) {
1255 objheader_t *headeraddr=&((objheader_t *) curr->val)[-1];
1256 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
1257 unsigned int version = headeraddr->version;
1258 /* versions do not match */
1259 if(version != header->version) {
1262 (typesCausingAbort[TYPE(header)])++;
1269 /* Then go through all objects that are read and are currently present in the readLockedArray */
1270 if(numoidrdlocked>0) {
1272 for(i=0; i<numoidrdlocked; i++) {
1273 objheader_t *header = ((void **)oidrdlocked)[i];
1274 unsigned int version = oidrdversion[i];
1275 if(version != header->version) { /* versions do not match */
1278 (typesCausingAbort[TYPE(header)])++;
1289 * getReadAbortCount : Tells the number of aborts caused by objects that are read by
1290 * visiting the read array
1291 * params: int start, int stop are indexes to readLocked array
1292 * void *oidrdlocked = readLocked array
1293 * int *oidrdversion = version array
1295 int getReadAbortCount(int start, int stop, void *oidrdlocked, int *oidrdversion) {
1298 /* Go through oids read that are locked */
1299 for(i = start; i < stop; i++) {
1300 objheader_t *header = ((void **)oidrdlocked)[i];
1301 unsigned int version = oidrdversion[i];
1302 if(version != header->version) { /* versions do not match */
1305 (typesCausingAbort[TYPE(header)])++;
1315 * params: Object header, ptr to garbage collector
1316 * Locks an object that causes aborts
1318 objheader_t * needLock(objheader_t *header, void *gl) {
1321 while((lockstatus = pthread_mutex_trylock(header->objlock))
1322 && ((ptr = header->trec) == NULL)) { //retry
1325 if(lockstatus==0) { //acquired lock
1327 header->trec = trec;
1328 } else { //failed to get lock
1331 __asm__ __volatile__("":::"memory");
1332 //see if other thread is blocked
1333 if(ptr->blocked == 1) {
1334 //it might be block, so ignore lock and clear our blocked flag
1339 INTPTR ptrarray[]={1, (INTPTR)gl, (INTPTR) header};
1340 void *lockptr=header->objlock;
1341 stopforgc((struct garbagelist *)ptrarray);
1342 //grab lock and wait our turn
1343 pthread_mutex_lock(lockptr);
1345 header=(objheader_t *) ptrarray[2];
1347 pthread_mutex_lock(header->objptr);
1349 /* we have lock, so we are not blocked anymore */
1352 header->trec = trec;
1355 //trec->blocked is zero now
1357 /* Save the locked object */
1358 if (lockedobjs->offset<MAXOBJLIST) {
1359 lockedobjs->objs[lockedobjs->offset++]=header;
1361 struct objlist *tmp=malloc(sizeof(struct objlist));
1362 tmp->next=lockedobjs;
1363 tmp->objs[0]=header;