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;
28 int numTransCommit = 0;
29 int numTransAbort = 0;
31 int nSoftAbortCommit = 0;
32 int nSoftAbortAbort = 0;
36 /* Thread variable for locking/unlocking */
37 __thread threadrec_t *trec;
38 __thread struct objlist * lockedobjs;
40 int typesCausingAbort[TOTALNUMCLASSANDARRAY];
41 /******Keep track of objects and types causing aborts******/
42 /* TODO uncomment for later use
43 #define DEBUGSTMSTAT(args...) { \
48 #define DEBUGSTMSTAT(args...)
50 #define DEBUGSTMSTAT(args...)
54 #define DEBUGSTM(x...) printf(x);
56 #define DEBUGSTM(x...)
60 void * A_memcpy (void * dest, const void * src, size_t count);
62 #define A_memcpy memcpy
65 extern void * curr_heapbase;
66 extern void * curr_heapptr;
67 extern void * curr_heaptop;
70 /*** Global variables *****/
71 objlockstate_t *objlockscope;
74 * params: object header
75 * Increments the abort count for each object
77 void ABORTCOUNT(objheader_t * x) {
79 if (x->abortCount > MAXABORTS && (x->riskyflag != 1)) {
80 //makes riskflag sticky
81 pthread_mutex_lock(&lockedobjstore);
82 if (objlockscope->offset<MAXOBJLIST) {
83 x->objlock=&(objlockscope->lock[objlockscope->offset++]);
85 objlockstate_t *tmp=malloc(sizeof(objlockstate_t));
86 tmp->next=objlockscope;
88 x->objlock=&(tmp->lock[0]);
91 pthread_mutex_unlock(&lockedobjstore);
92 pthread_mutex_init(x->objlock, NULL);
93 //should put a memory barrier here
99 /* ==================================================
101 * This function starts up the transaction runtime.
102 * ==================================================
108 /* ======================================
110 * - create an object store of given size
111 * ======================================
113 objstr_t *objstrCreate(unsigned int size) {
115 if((tmp = calloc(1, (sizeof(objstr_t) + size))) == NULL) {
116 printf("%s() Calloc error at line %d, %s\n", __func__, __LINE__, __FILE__);
121 tmp->top = tmp + 1; //points to end of objstr_t structure!
126 while(t_cache->next!=NULL) {
127 objstr_t *next=t_cache->next;
128 t_cache->next=t_reserve;
132 t_cache->top=t_cache+1;
135 //free entire list, starting at store
136 void objstrDelete(objstr_t *store) {
138 while (store != NULL) {
146 /* =================================================
148 * This function initializes things required in the
150 * =================================================
153 //Transaction start is currently free...commit and aborting is not
156 /* =======================================================
158 * This function creates objects in the transaction record
159 * =======================================================
161 objheader_t *transCreateObj(void * ptr, unsigned int size) {
162 objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
163 objheader_t *retval=&tmp[1];
164 tmp->lock=RW_LOCK_BIAS;
166 //initialize obj lock to the header
168 // don't insert into table
169 if (newobjs->offset<MAXOBJLIST) {
170 newobjs->objs[newobjs->offset++]=retval;
172 struct objlist *tmp=malloc(sizeof(struct objlist));
178 return retval; //want space after object header
181 /* This functions inserts randowm wait delays in the order of msec
182 * Mostly used when transaction commits retry*/
183 void randomdelay(int softaborted) {
187 gettimeofday(&t,NULL);
190 req.tv_nsec = (long)((t.tv_usec)%(1<<softaborted))<<1; //1-11 microsec
191 nanosleep(&req, NULL);
195 /* ==============================================
197 * - allocate space in an object store
198 * ==============================================
200 void *objstrAlloc(unsigned int size) {
203 objstr_t *store=t_cache;
209 if (OSFREE(store)>=size) {
214 if ((store=store->next)==NULL)
219 unsigned int newsize=size>DEFAULT_OBJ_STORE_SIZE ? size : DEFAULT_OBJ_STORE_SIZE;
220 objstr_t **otmp=&t_reserve;
222 while((ptr=*otmp)!=NULL) {
223 if (ptr->size>=newsize) {
228 ptr->top=((char *)(&ptr[1]))+size;
233 objstr_t *os=(objstr_t *)calloc(1,(sizeof(objstr_t) + newsize));
238 os->top=((char *)nptr)+size;
243 /* =============================================================
245 * -finds the objects either in main heap
246 * -copies the object into the transaction cache
247 * =============================================================
249 __attribute__((pure)) void *transRead(void * oid, void *gl) {
250 objheader_t *tmp, *objheader;
251 objheader_t *objcopy;
254 /* Read from the main heap */
256 objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
257 GETSIZE(size, header);
258 size += sizeof(objheader_t);
259 objcopy = (objheader_t *) objstrAlloc(size);
261 header->accessCount++;
262 if(header->riskyflag) {
263 header=needLock(header,gl);
266 A_memcpy(objcopy, header, size);
267 /* Insert into cache's lookup table */
269 if (((unsigned int)oid)<((unsigned int ) curr_heapbase)|| ((unsigned int)oid) >((unsigned int) curr_heapptr))
270 printf("ERROR! Bad object address!\n");
271 t_chashInsert(oid, &objcopy[1]);
276 struct objlist *ptr=newobjs;
277 while(ptr->next!=NULL) {
278 struct objlist *tmp=ptr->next;
287 void freelockedobjs() {
288 struct objlist *ptr=lockedobjs;
289 while(ptr->next!=NULL) {
290 struct objlist *tmp=ptr->next;
299 /* ================================================================
301 * - This function initiates the transaction commit process
302 * - goes through the transaction cache and decides
304 * ================================================================
307 int transCommit(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
313 /* Look through all the objects in the transaction hash table */
316 if (c_numelements<(c_size>>3))
317 finalResponse= alttraverseCache(commitmethod, primitives, locals, params);
319 finalResponse= traverseCache(commitmethod, primitives, locals, params);
321 if (c_numelements<(c_size>>3))
322 finalResponse= alttraverseCache();
324 finalResponse= traverseCache();
326 if(finalResponse == TRANS_ABORT) {
346 if(finalResponse == TRANS_COMMIT) {
366 /* wait a random amount of time before retrying to commit transaction*/
367 if(finalResponse == TRANS_SOFT_ABORT) {
377 //retry if too many soft aborts
391 //randomdelay(softaborted);
393 printf("Error: in %s() Unknown outcome", __func__);
400 #define freearrays if (c_numelements>=200) { \
402 free(oidrdversion); \
404 if (t_numelements>=200) { \
408 #define freearrays if (c_numelements>=200) { \
410 free(oidrdversion); \
414 /* ==================================================
416 * - goes through the transaction cache and
417 * - decides if a transaction should commit or abort
418 * ==================================================
421 int traverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
423 int traverseCache() {
425 /* Create info to keep track of objects that can be locked */
426 int numoidrdlocked=0;
427 int numoidwrlocked=0;
428 void * rdlocked[200];
430 void * wrlocked[200];
437 int t_numelements=c_numelements+dc_c_numelements;
438 if (t_numelements<200) {
439 oidwrlocked=wrlocked;
441 oidwrlocked=malloc(t_numelements*sizeof(void *));
443 if (c_numelements<200) {
444 oidrdlocked=rdlocked;
445 oidrdversion=rdversion;
447 int size=c_numelements*sizeof(void*);
448 oidrdlocked=malloc(size);
449 oidrdversion=malloc(size);
452 if (c_numelements<200) {
453 oidrdlocked=rdlocked;
454 oidrdversion=rdversion;
455 oidwrlocked=wrlocked;
457 int size=c_numelements*sizeof(void*);
458 oidrdlocked=malloc(size);
459 oidrdversion=malloc(size);
460 oidwrlocked=malloc(size);
463 chashlistnode_t *ptr = c_table;
464 /* Represents number of bins in the chash table */
465 unsigned int size = c_size;
466 for(i = 0; i<size; i++) {
467 chashlistnode_t *curr = &ptr[i];
468 /* Inner loop to traverse the linked list of the cache lookupTable */
469 while(curr != NULL) {
470 //if the first bin in hash table is empty
471 if(curr->key == NULL)
473 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
474 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
475 unsigned int version = headeraddr->version;
477 if(STATUS(headeraddr) & DIRTY) {
478 /* Read from the main heap and compare versions */
479 if(write_trylock(&header->lock)) { //can aquire write lock
480 if (version == header->version) { /* versions match */
481 /* Keep track of objects locked */
482 oidwrlocked[numoidwrlocked++] = header;
484 oidwrlocked[numoidwrlocked++] = header;
485 transAbortProcess(oidwrlocked, numoidwrlocked);
488 (typesCausingAbort[TYPE(header)])++;
489 getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1);
491 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
492 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
495 return TRANS_SOFT_ABORT;
500 if(version == header->version) {
504 transAbortProcess(oidwrlocked, numoidwrlocked);
507 (typesCausingAbort[TYPE(header)])++;
509 #if defined(STMSTATS)||defined(SOFTABORT)
510 if (getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1))
513 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
514 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
517 return TRANS_SOFT_ABORT;
522 oidrdversion[numoidrdlocked]=version;
523 oidrdlocked[numoidrdlocked++] = header;
530 //acquire other locks
531 unsigned int numoidwrtotal=numoidwrlocked;
533 chashlistnode_t *dc_curr = dc_c_list;
534 /* Inner loop to traverse the linked list of the cache lookupTable */
535 while(likely(dc_curr != NULL)) {
536 //if the first bin in hash table is empty
537 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
538 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
539 if(write_trylock(&header->lock)) { //can aquire write lock
540 oidwrlocked[numoidwrtotal++] = header;
542 //maybe we already have lock
543 void * key=dc_curr->key;
544 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
547 if(node->key == key) {
551 } while(node != NULL);
553 //have to abort to avoid deadlock
554 transAbortProcess(oidwrlocked, numoidwrlocked);
557 (typesCausingAbort[TYPE(header)])++;
559 #if defined(STMSTATS)||defined(SOFTABORT)
560 if (getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1))
563 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
564 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
567 return TRANS_SOFT_ABORT;
572 dc_curr = dc_curr->lnext;
576 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
578 for(i=0; i<numoidrdlocked; i++) {
579 /* Read from the main heap and compare versions */
580 objheader_t *header=oidrdlocked[i];
581 unsigned int version=oidrdversion[i];
582 if(header->lock>0) { //not write locked
583 if(version != header->version) { /* versions do not match */
584 oidrdlocked[numoidrdlocked++] = header;
585 transAbortProcess(oidwrlocked, numoidwrlocked);
588 (typesCausingAbort[TYPE(header)])++;
589 getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *) oidrdversion, 0);
591 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
592 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
596 } else { /* cannot aquire lock */
597 //do increment as we didn't get lock
598 if(version == header->version) {
601 transAbortProcess(oidwrlocked, numoidwrlocked);
604 (typesCausingAbort[TYPE(header)])++;
606 #if defined(STMSTATS)||defined(SOFTABORT)
607 if (getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *) oidrdversion, 0))
610 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
611 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
614 return TRANS_SOFT_ABORT;
620 /* Decide the final response */
622 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
624 transCommitProcess(oidwrlocked, numoidwrlocked);
626 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
631 /* ==================================================
633 * - goes through the transaction cache and
634 * - decides if a transaction should commit or abort
635 * ==================================================
639 int alttraverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
641 int alttraverseCache() {
643 /* Create info to keep track of objects that can be locked */
644 int numoidrdlocked=0;
645 int numoidwrlocked=0;
646 void * rdlocked[200];
648 void * wrlocked[200];
655 int t_numelements=c_numelements+dc_c_numelements;
656 if (t_numelements<200) {
657 oidwrlocked=wrlocked;
659 oidwrlocked=malloc(t_numelements*sizeof(void *));
661 if (c_numelements<200) {
662 oidrdlocked=rdlocked;
663 oidrdversion=rdversion;
665 int size=c_numelements*sizeof(void*);
666 oidrdlocked=malloc(size);
667 oidrdversion=malloc(size);
670 if (c_numelements<200) {
671 oidrdlocked=rdlocked;
672 oidrdversion=rdversion;
673 oidwrlocked=wrlocked;
675 int size=c_numelements*sizeof(void*);
676 oidrdlocked=malloc(size);
677 oidrdversion=malloc(size);
678 oidwrlocked=malloc(size);
681 chashlistnode_t *curr = c_list;
682 /* Inner loop to traverse the linked list of the cache lookupTable */
683 while(likely(curr != NULL)) {
684 //if the first bin in hash table is empty
685 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
686 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
687 unsigned int version = headeraddr->version;
689 if(STATUS(headeraddr) & DIRTY) {
690 /* Read from the main heap and compare versions */
691 if(likely(write_trylock(&header->lock))) { //can aquire write lock
692 if (likely(version == header->version)) { /* versions match */
693 /* Keep track of objects locked */
694 oidwrlocked[numoidwrlocked++] = header;
696 oidwrlocked[numoidwrlocked++] = header;
697 transAbortProcess(oidwrlocked, numoidwrlocked);
700 (typesCausingAbort[TYPE(header)])++;
701 getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1);
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);
708 } else { /* cannot aquire lock */
709 if(version == header->version) {
713 transAbortProcess(oidwrlocked, numoidwrlocked);
716 (typesCausingAbort[TYPE(header)])++;
718 #if defined(STMSTATS)||defined(SOFTABORT)
719 if (getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1))
722 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
723 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
726 return TRANS_SOFT_ABORT;
731 /* Read from the main heap and compare versions */
732 oidrdversion[numoidrdlocked]=version;
733 oidrdlocked[numoidrdlocked++] = header;
739 //acquire other locks
740 unsigned int numoidwrtotal=numoidwrlocked;
741 chashlistnode_t *dc_curr = dc_c_list;
742 /* Inner loop to traverse the linked list of the cache lookupTable */
743 while(likely(dc_curr != NULL)) {
744 //if the first bin in hash table is empty
745 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
746 objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
747 if(write_trylock(&header->lock)) { //can aquire write lock
748 oidwrlocked[numoidwrtotal++] = header;
750 //maybe we already have lock
751 void * key=dc_curr->key;
752 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
755 if(node->key == key) {
759 } while(node != NULL);
761 //have to abort to avoid deadlock
762 transAbortProcess(oidwrlocked, numoidwrlocked);
765 (typesCausingAbort[TYPE(header)])++;
767 #if defined(STMSTATS)||defined(SOFTABORT)
768 if (getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1))
771 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
772 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
775 return TRANS_SOFT_ABORT;
780 dc_curr = dc_curr->lnext;
784 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
786 for(i=0; i<numoidrdlocked; i++) {
787 objheader_t * header=oidrdlocked[i];
788 unsigned int version=oidrdversion[i];
789 if(header->lock>=0) {
790 if(version != header->version) {
791 transAbortProcess(oidwrlocked, numoidwrlocked);
794 (typesCausingAbort[TYPE(header)])++;
795 getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0);
797 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
798 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
802 } else { /* cannot aquire lock */
803 if(version == header->version) {
806 transAbortProcess(oidwrlocked, numoidwrlocked);
809 (typesCausingAbort[TYPE(header)])++;
811 #if defined(STMSTATS)||defined(SOFTABORT)
812 if (getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0))
815 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
816 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
819 return TRANS_SOFT_ABORT;
825 /* Decide the final response */
827 transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
829 transCommitProcess(oidwrlocked, numoidwrlocked);
831 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
837 int altalttraverseCache() {
838 /* Create info to keep track of objects that can be locked */
839 int numoidrdlocked=0;
840 int numoidwrlocked=0;
841 void * rdlocked[200];
843 void * wrlocked[200];
849 if (c_numelements<200) {
850 oidrdlocked=rdlocked;
851 oidrdversion=rdversion;
852 oidwrlocked=wrlocked;
854 int size=c_numelements*sizeof(void*);
855 oidrdlocked=malloc(size);
856 oidrdversion=malloc(size);
857 oidwrlocked=malloc(size);
860 objstr_t * curr=t_cache;
862 while(curr != NULL) {
865 for(bottom=(char *)(curr+1);bottom < ((char *)curr->top);) {
866 objheader_t *headeraddr=(objheader_t *)bottom;
867 objheader_t *header=OID(headeraddr)-sizeof(objheader_t);
868 unsigned int version = headeraddr->version;
870 if(STATUS(headeraddr) & DIRTY) {
871 /* Read from the main heap and compare versions */
872 if(likely(write_trylock(&header->lock))) { //can aquire write lock
873 if (likely(version == header->version)) { /* versions match */
874 /* Keep track of objects locked */
875 oidwrlocked[numoidwrlocked++] = header;
877 oidwrlocked[numoidwrlocked++] = header;
878 transAbortProcess(oidwrlocked, numoidwrlocked);
881 (typesCausingAbort[TYPE(header)])++;
882 //getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1);
884 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
885 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
886 if (c_numelements>=200) {
893 } else { /* cannot aquire lock */
894 if(version == header->version) {
898 transAbortProcess(oidwrlocked, numoidwrlocked);
901 (typesCausingAbort[TYPE(header)])++;
903 #if defined(STMSTATS)||defined(SOFTABORT)
904 // if (getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1))
907 DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
908 DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
909 if (c_numelements>=200) {
915 return TRANS_SOFT_ABORT;
920 /* Read from the main heap and compare versions */
921 oidrdversion[numoidrdlocked]=version;
922 oidrdlocked[numoidrdlocked++] = header;
925 GETSIZE(size, headeraddr);
926 size+=sizeof(objheader_t);
934 //THIS IS THE SERIALIZATION POINT *****
935 for(i=0; i<numoidrdlocked; i++) {
936 objheader_t * header = oidrdlocked[i];
937 unsigned int version=oidrdversion[i];
938 if(header->lock>=0) {
939 if(version != header->version) {
940 transAbortProcess(oidwrlocked, numoidwrlocked);
943 (typesCausingAbort[TYPE(header)])++;
944 getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0);
946 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
947 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
948 if (c_numelements>=200) {
955 } else { /* cannot aquire lock */
956 if(version == header->version) {
959 transAbortProcess(oidwrlocked, numoidwrlocked);
962 (typesCausingAbort[TYPE(header)])++;
964 #if defined(STMSTATS)||defined(SOFTABORT)
965 if (getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0))
968 DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
969 DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
970 if (c_numelements>=200) {
976 return TRANS_SOFT_ABORT;
982 /* Decide the final response */
983 transCommitProcess(oidwrlocked, numoidwrlocked);
984 DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
985 if (c_numelements>=200) {
994 /* ==================================
997 * =================================
999 void transAbortProcess(void **oidwrlocked, int numoidwrlocked) {
1001 objheader_t *header;
1002 /* Release read locks */
1004 /* Release write locks */
1005 for(i=numoidwrlocked-1; i>=0; i--) {
1006 /* Read from the main heap */
1007 header = (objheader_t *)oidwrlocked[i];
1008 write_unlock(&header->lock);
1012 /* clear trec and then release objects locked */
1013 struct objlist *ptr=lockedobjs;
1015 int max=ptr->offset;
1016 for(i=max-1; i>=0; i--) {
1017 header = (objheader_t *)ptr->objs[i];
1018 header->trec = NULL;
1019 pthread_mutex_unlock(header->objlock);
1026 /* ==================================
1027 * transCommitProcess
1029 * =================================
1032 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked, int numoidwrtotal, void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
1034 void transCommitProcess(void ** oidwrlocked, int numoidwrlocked) {
1036 objheader_t *header;
1039 struct objlist *ptr=newobjs;
1041 int max=ptr->offset;
1042 for(i=0; i<max; i++) {
1043 //clear the new flag
1044 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
1049 /* Copy from transaction cache -> main object store */
1050 for (i = numoidwrlocked-1; i >=0; i--) {
1051 /* Read from the main heap */
1052 header = (objheader_t *)oidwrlocked[i];
1054 GETSIZE(tmpsize, header);
1055 struct ___Object___ *dst=(struct ___Object___*)(((char *)oidwrlocked[i])+sizeof(objheader_t));
1056 struct ___Object___ *src=t_chashSearch(dst);
1057 dst->___cachedCode___=src->___cachedCode___;
1058 dst->___cachedHash___=src->___cachedHash___;
1059 A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
1060 __asm__ __volatile__("": : :"memory");
1063 __asm__ __volatile__("": : :"memory");
1066 // call commit method
1069 commitmethod(params, locals, primitives);
1072 /* Release write locks */
1074 for(i=numoidwrtotal-1; i>=0; i--) {
1076 for(i=numoidwrlocked-1; i>=0; i--) {
1078 header = (objheader_t *)oidwrlocked[i];
1079 write_unlock(&header->lock);
1083 /* clear trec and then release objects locked */
1086 int max=ptr->offset;
1087 for(i=max-1; i>=0; i--) {
1088 header = (objheader_t *)ptr->objs[i];
1089 header->trec = NULL;
1090 pthread_mutex_unlock(header->objlock);
1097 /** ========================================================================================
1098 * getTotalAbortCount
1099 * params : start: start index of the loop
1100 * : stop: stop index of the loop
1101 * : startptr: pointer that points to where to start looking in the array/ linked list
1102 * 0='r'/1='w' if found when visiting objects read/ objects modified
1103 * =========================================================================================
1105 #if defined(STMSTATS)||defined(SOFTABORT)
1106 int getTotalAbortCount(int start, int stop, void *startptr, void *checkptr, int type) {
1110 int isFirstTime = 0;
1111 chashlistnode_t *curr = (chashlistnode_t *) startptr;
1112 chashlistnode_t *ptr = c_table;
1113 for(i = start; i < stop; i++) {
1116 /* Inner loop to traverse the linked list of the cache lookupTable */
1117 while(curr != NULL) {
1118 if(curr->key == NULL)
1120 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
1121 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
1122 unsigned int version = headeraddr->version;
1123 /* versions do not match */
1124 if(version != header->version) {
1127 (typesCausingAbort[TYPE(header)])++;
1136 /* Go through oids read that are locked */
1137 for(i = start; i < stop; i++) {
1138 objheader_t *header = ((void **)startptr)[i];
1139 unsigned int version = ((int *)checkptr)[i];
1140 if(version != header->version) { /* versions do not match */
1143 (typesCausingAbort[TYPE(header)])++;
1154 * params: Object header
1155 * Locks an object that causes aborts
1157 objheader_t * needLock(objheader_t *header, void *gl) {
1160 while((lockstatus = pthread_mutex_trylock(header->objlock))
1161 && ((ptr = header->trec) == NULL)) { //retry
1164 if(lockstatus==0) { //acquired lock
1166 header->trec = trec;
1167 } else { //failed to get lock
1170 __asm__ __volatile__("":::"memory");
1171 //see if other thread is blocked
1172 if(ptr->blocked == 1) {
1173 //it might be block, so ignore lock and clear our blocked flag
1178 INTPTR ptrarray[]={1, (INTPTR)gl, (INTPTR) header};
1179 void *lockptr=header->objlock;
1180 stopforgc((struct garbagelist *)ptrarray);
1181 //grab lock and wait our turn
1182 pthread_mutex_lock(lockptr);
1184 header=(objheader_t *) ptrarray[2];
1186 pthread_mutex_lock(header->objptr);
1188 /* we have lock, so we are not blocked anymore */
1191 header->trec = trec;
1194 //trec->blocked is zero now
1196 /* Save the locked object */
1197 if (lockedobjs->offset<MAXOBJLIST) {
1198 lockedobjs->objs[lockedobjs->offset++]=header;
1200 struct objlist *tmp=malloc(sizeof(struct objlist));
1201 tmp->next=lockedobjs;
1202 tmp->objs[0]=header;