19 #define STATFREE free(oidrdage);
20 #define STATALLOC oidrdage=malloc(size);
21 #define STATASSIGN oidrdage=rdage;
28 /* ================================================================
30 * - This function initiates the transaction commit process
31 * - goes through the transaction cache and decides
33 * ================================================================
36 int transCommit(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
43 TRANSWRAP(numTransCommit++;);
46 /* Look through all the objects in the transaction hash table */
48 if (c_numelements<(c_size>>3))
49 finalResponse=alttraverseCache(DELAYWRAP(commitmethod, primitives, locals, params));
51 finalResponse=traverseCache(DELAYWRAP(commitmethod, primitives, locals, params));
52 if(finalResponse == TRANS_ABORT) {
53 TRANSWRAP(numTransAbort++;if (softaborted) nSoftAbortAbort++;);
55 STMWRAP(freelockedobjs(););
72 if(finalResponse == TRANS_COMMIT) {
73 TRANSWRAP(numTransCommit++;if (softaborted) nSoftAbortCommit++;);
75 STMWRAP(freelockedobjs(););
90 /* wait a random amount of time before retrying to commit transaction*/
91 if(finalResponse == TRANS_SOFT_ABORT) {
92 TRANSWRAP(nSoftAbort++;);
99 //retry if too many soft aborts
101 STMWRAP(freelockedobjs(););
116 printf("Error: in %s() Unknown outcome", __func__);
123 #define freearrays if (c_numelements>=200) { \
127 free(oidrdversion); \
129 if (t_numelements>=200) { \
133 #define freearrays if (c_numelements>=200) { \
137 free(oidrdversion); \
143 #define allocarrays int t_numelements=c_numelements+dc_c_numelements; \
144 if (t_numelements<200) { \
145 oidwrlocked=(struct garbagelist *) &wrlocked; \
147 oidwrlocked=malloc(2*sizeof(INTPTR)+t_numelements*sizeof(void *)); \
149 if (c_numelements<200) { \
150 oidrdlocked=rdlocked; \
151 oidrdversion=rdversion; \
155 int size=c_numelements*sizeof(void*); \
156 oidrdlocked=malloc(size); \
157 oidrdversion=malloc(size); \
161 dirwrlocked=oidwrlocked->array;
163 #define allocarrays if (c_numelements<200) { \
164 oidrdlocked=rdlocked; \
165 oidrdversion=rdversion; \
166 oidwrlocked=(struct garbagelist *) &wrlocked; \
170 int size=c_numelements*sizeof(void*); \
171 oidrdlocked=malloc(size); \
172 oidrdversion=malloc(size); \
173 oidwrlocked=malloc(size+2*sizeof(INTPTR)); \
177 dirwrlocked=oidwrlocked->array;
181 #define ABORTSTAT1 header->abortCount++; \
182 ObjSeqId = headeraddr->accessCount; \
183 (typesCausingAbort[TYPE(header)]).numabort++; \
184 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements; \
185 (typesCausingAbort[TYPE(header)]).numtrans+=1; \
186 objtypetraverse[TYPE(header)]=1; \
187 if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse)) \
190 ObjSeqId = oidrdage[i];\
191 header->abortCount++; \
192 (typesCausingAbort[TYPE(header)]).numabort++; \
193 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements; \
194 (typesCausingAbort[TYPE(header)]).numtrans+=1; \
195 objtypetraverse[TYPE(header)]=1; \
196 if (getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse)) \
199 header->abortCount++; \
200 ObjSeqId = headeraddr->accessCount; \
201 (typesCausingAbort[TYPE(header)]).numabort++; \
202 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements; \
203 (typesCausingAbort[TYPE(header)]).numtrans+=1; \
204 objtypetraverse[TYPE(header)]=1; \
205 if (getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse)) \
207 #define ABORTSTAT4 ObjSeqId = oidrdage[i]; \
208 header->abortCount++; \
209 getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion, oidrdage, ObjSeqId, header, objtypetraverse);
218 #define DELAYWRAP(x) x
219 #define NUMWRTOTAL numoidwrtotal
222 #define NUMWRTOTAL numoidwrlocked
226 #define STMARRAYFREE free(oidrdlockedarray);
227 #define STMARRAYALLOC oidrdlockedarray=malloc(size);
228 #define STMARRAYASSIGN oidrdlockedarray=rdlockedarray;
230 #define ARRAYDEFINES int numoidrdlockedarray=0; \
231 void * rdlockedarray[200]; \
232 void ** oidrdlockedarray;
234 #define PROCESSARRAY \
235 int type=((int *)cachedobj)[0]; \
236 if (type>=NUMCLASSES) { \
237 struct ArrayObject *transao=(struct ArrayObject *) cachedobj; \
238 struct ArrayObject *mainao=(struct ArrayObject *) objptr; \
239 int lowoffset=(transao->lowoffset)>>INDEXSHIFT; \
240 int highoffset=(transao->highoffset)>>INDEXSHIFT; \
242 int addwrobject=0, addrdobject=0; \
243 for(j=lowoffset; j<=highoffset;j++) { \
245 GETLOCKVAL(status, transao, j); \
246 if (status==STMDIRTY) { \
247 unsigned int * lockptr; \
248 GETLOCKPTR(lockptr, mainao,j); \
249 if (write_trylock(lockptr)) { \
250 unsigned int localversion; \
251 unsigned int remoteversion; \
252 GETVERSIONVAL(localversion, transao, j); \
253 GETVERSIONVAL(remoteversion, mainao, j); \
254 if (localversion == remoteversion) { \
257 dirwrlocked[numoidwrlocked++] = objptr; \
258 transAbortProcess(oidwrlocked, numoidwrlocked); \
261 return TRANS_SOFT_ABORT; \
263 return TRANS_ABORT; \
266 } else if (status==STMCLEAN) { \
271 dirwrlocked[numoidwrlocked++] = objptr; \
274 rdlockedarray[numrdlockedarray++]=objptr; \
278 #define READDARRAYS \
279 for(i=0; i<numoidrdlockedarray; i++) { \
280 objheader_t * transheader=oidrdlockedarray[i]; \
281 struct ArrayObject * transao=(struct ArrayObject *)&transheader[1]; \
282 objheader_t * mainheader=OID(transheader); \
283 struct ArrayObject * mainao=(struct ArrayObject *)&transheader[1]; \
284 int lowoffset=(transao->lowoffset)>>INDEXSHIFT; \
285 int highoffset=(transao->highoffset)>>INDEXSHIFT; \
287 for(j=lowoffset; j<=highoffset;j++) { \
288 int locallock;GETLOCKVAL(locallock,transao,j); \
289 if (locallock==STMCLEAN) { \
290 /* do read check */ \
291 int mainlock; GETLOCKVAL(mainlock, mainao, j); \
294 unsigned int localversion; \
295 unsigned int remoteversion; \
296 GETVERSIONVAL(localversion, transao, j); \
297 GETVERSIONVAL(remoteversion, mainao, j); \
298 if (localversion != remoteversion) { \
299 transAbortProcess(oidwrlocked, NUMWRTOTAL); \
301 return TRANS_ABORT; \
312 #define STMARRAYALLOC
313 #define STMARRAYASSIGN
316 /* ==================================================
318 * - goes through the transaction cache and
319 * - decides if a transaction should commit or abort
320 * ==================================================
323 int traverseCache(DELAYWRAP(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params)) {
324 /* Create info to keep track of objects that can be locked */
325 int numoidrdlocked=0;
326 int numoidwrlocked=0;
327 void * rdlocked[200];
329 struct fixedlist wrlocked;
335 STMWRAP(int rdage[200];int * oidrdage;int ObjSeqId;int objtypetraverse[TOTALNUMCLASSANDARRAY];);
336 struct garbagelist * oidwrlocked;
340 STMWRAP(for(i=0; i<TOTALNUMCLASSANDARRAY; i++) objtypetraverse[i] = 0;);
342 chashlistnode_t *ptr = c_table;
343 /* Represents number of bins in the chash table */
344 unsigned int size = c_size;
345 for(i = 0; i<size; i++) {
346 chashlistnode_t *curr = &ptr[i];
347 /* Inner loop to traverse the linked list of the cache lookupTable */
348 while(curr != NULL) {
349 //if the first bin in hash table is empty
350 if(curr->key == NULL)
352 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1]; //cached object
353 void * objptr=curr->key;
354 objheader_t *header=(objheader_t *)(((char *)objptr)-sizeof(objheader_t)); //real object
355 unsigned int version = headeraddr->version;
359 if(STATUS(headeraddr) & DIRTY) {
360 /* Read from the main heap and compare versions */
361 if(write_trylock(&header->lock)) { //can aquire write lock
362 if (version == header->version) { /* versions match */
363 /* Keep track of objects locked */
364 dirwrlocked[numoidwrlocked++] = objptr;
366 dirwrlocked[numoidwrlocked++] = objptr;
367 transAbortProcess(oidwrlocked, numoidwrlocked);
371 return TRANS_SOFT_ABORT;
376 if(version == header->version) {
380 transAbortProcess(oidwrlocked, numoidwrlocked);
384 return TRANS_SOFT_ABORT;
390 STMWRAP(oidrdage[numoidrdlocked]=headeraddr->accessCount;);
391 oidrdversion[numoidrdlocked]=version;
392 oidrdlocked[numoidrdlocked++]=header;
399 //acquire access set locks
400 unsigned int numoidwrtotal=numoidwrlocked;
402 chashlistnode_t *dc_curr = dc_c_list;
403 /* Inner loop to traverse the linked list of the cache lookupTable */
404 while(likely(dc_curr != NULL)) {
405 //if the first bin in hash table is empty
406 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
407 void *objptr=dc_curr->key;
408 objheader_t *header=(objheader_t *)(((char *)objptr)-sizeof(objheader_t));
409 if(write_trylock(&header->lock)) { //can aquire write lock
410 dirwrlocked[numoidwrtotal++] = objptr;
412 //maybe we already have lock
413 void * key=dc_curr->key;
414 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
417 if(node->key == key) {
418 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
419 if(STATUS(headeraddr) & DIRTY) {
425 } while(node != NULL);
427 //have to abort to avoid deadlock
428 transAbortProcess(oidwrlocked, numoidwrtotal);
432 return TRANS_SOFT_ABORT;
437 dc_curr = dc_curr->lnext;
441 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
445 for(i=0; i<numoidrdlocked; i++) {
446 /* Read from the main heap and compare versions */
447 objheader_t *header=oidrdlocked[i];
448 unsigned int version=oidrdversion[i];
449 if(header->lock>0) { //not write locked
451 if(version != header->version) { /* versions do not match */
452 transAbortProcess(oidwrlocked, NUMWRTOTAL);
458 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
459 //couldn't get lock because we already have it
460 //check if it is the right version number
461 if (version!=header->version) {
462 transAbortProcess(oidwrlocked, numoidwrtotal);
468 } else { /* cannot aquire lock */
469 //do increment as we didn't get lock
470 if(version == header->version) {
473 transAbortProcess(oidwrlocked, NUMWRTOTAL);
477 return TRANS_SOFT_ABORT;
484 //need to validate auxilary readset
485 rdchashlistnode_t *rd_curr = rd_c_list;
486 /* Inner loop to traverse the linked list of the cache lookupTable */
487 while(likely(rd_curr != NULL)) {
488 //if the first bin in hash table is empty
489 unsigned int version=rd_curr->version;
490 objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
491 if(header->lock>0) { //object is not locked
492 if (version!=header->version) {
494 transAbortProcess(oidwrlocked, NUMWRTOTAL);
495 STMWRAP((typesCausingAbort[TYPE(header)])++;);
498 return TRANS_SOFT_ABORT;
503 //maybe we already have lock
504 if (version==header->version) {
505 void * key=rd_curr->key;
507 //check to see if it is in the delaycomp table
509 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
514 } while(node != NULL);
519 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
521 if(node->key == key) {
522 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
523 if(STATUS(headeraddr) & DIRTY) {
528 } while(node != NULL);
531 //have to abort to avoid deadlock
532 transAbortProcess(oidwrlocked, NUMWRTOTAL);
533 STMWRAP((typesCausingAbort[TYPE(header)])++;);
536 return TRANS_SOFT_ABORT;
541 rd_curr = rd_curr->lnext;
545 /* Decide the final response */
546 transCommitProcess(oidwrlocked, numoidwrlocked DELAYWRAP(, numoidwrtotal, commitmethod, primitives, locals, params));
551 /* ==================================================
553 * - goes through the transaction cache and
554 * - decides if a transaction should commit or abort
555 * ==================================================
558 int alttraverseCache(DELAYWRAP(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params)) {
559 /* Create info to keep track of objects that can be locked */
560 int numoidrdlocked=0;
561 int numoidwrlocked=0;
562 void * rdlocked[200];
564 struct fixedlist wrlocked;
569 STMWRAP(int rdage[200];int * oidrdage;int ObjSeqId;int objtypetraverse[TOTALNUMCLASSANDARRAY];);
571 struct garbagelist * oidwrlocked;
575 STMWRAP(for(i=0; i<TOTALNUMCLASSANDARRAY; i++) objtypetraverse[i] = 0;);
577 chashlistnode_t *curr = c_list;
578 /* Inner loop to traverse the linked list of the cache lookupTable */
579 while(likely(curr != NULL)) {
580 //if the first bin in hash table is empty
581 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
582 void *objptr=curr->key;
583 objheader_t *header=(objheader_t *)(((char *)objptr)-sizeof(objheader_t));
584 unsigned int version = headeraddr->version;
588 if(STATUS(headeraddr) & DIRTY) {
589 /* Read from the main heap and compare versions */
590 if(likely(write_trylock(&header->lock))) { //can aquire write lock
591 if (likely(version == header->version)) { /* versions match */
592 /* Keep track of objects locked */
593 dirwrlocked[numoidwrlocked++] = objptr;
595 dirwrlocked[numoidwrlocked++] = objptr;
596 transAbortProcess(oidwrlocked, numoidwrlocked);
601 } else { /* cannot aquire lock */
602 if(version == header->version) {
606 transAbortProcess(oidwrlocked, numoidwrlocked);
610 return TRANS_SOFT_ABORT;
615 /* Read from the main heap and compare versions */
616 oidrdversion[numoidrdlocked]=version;
617 oidrdlocked[numoidrdlocked++] = header;
623 //acquire other locks
624 unsigned int numoidwrtotal=numoidwrlocked;
625 chashlistnode_t *dc_curr = dc_c_list;
626 /* Inner loop to traverse the linked list of the cache lookupTable */
627 while(likely(dc_curr != NULL)) {
628 //if the first bin in hash table is empty
629 objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
630 void *objptr=dc_curr->key;
631 objheader_t *header=(objheader_t *)(((char *)objptr)-sizeof(objheader_t));
632 if(write_trylock(&header->lock)) { //can aquire write lock
633 dirwrlocked[numoidwrtotal++] = objptr;
635 //maybe we already have lock
636 void * key=dc_curr->key;
637 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
640 if(node->key == key) {
641 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
642 if(STATUS(headeraddr) & DIRTY) {
647 } while(node != NULL);
649 //have to abort to avoid deadlock
650 transAbortProcess(oidwrlocked, numoidwrtotal);
654 return TRANS_SOFT_ABORT;
659 dc_curr = dc_curr->lnext;
663 //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
667 for(i=0; i<numoidrdlocked; i++) {
668 objheader_t * header=oidrdlocked[i];
669 unsigned int version=oidrdversion[i];
672 if(version != header->version) {
673 transAbortProcess(oidwrlocked, NUMWRTOTAL);
679 } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
680 //couldn't get lock because we already have it
681 //check if it is the right version number
682 if (version!=header->version) {
683 transAbortProcess(oidwrlocked, numoidwrtotal);
689 } else { /* cannot aquire lock */
690 if(version == header->version) {
693 transAbortProcess(oidwrlocked, NUMWRTOTAL);
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 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) {
714 transAbortProcess(oidwrlocked, NUMWRTOTAL);
715 STMWRAP((typesCausingAbort[TYPE(header)])++;);
718 return TRANS_SOFT_ABORT;
723 if (version==header->version) {
724 void * key=rd_curr->key;
726 //check to see if it is in the delaycomp table
728 chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
733 } while(node != NULL);
738 chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
740 if(node->key == key) {
741 objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
742 if(STATUS(headeraddr) & DIRTY) {
747 } while(node != NULL);
750 //have to abort to avoid deadlock
751 transAbortProcess(oidwrlocked, NUMWRTOTAL);
752 STMWRAP((typesCausingAbort[TYPE(header)])++;);
755 return TRANS_SOFT_ABORT;
760 rd_curr = rd_curr->lnext;
764 /* Decide the final response */
765 transCommitProcess(oidwrlocked, numoidwrlocked DELAYWRAP(, numoidwrtotal, commitmethod, primitives, locals, params));
770 /* ==================================
773 * =================================
778 void transAbortProcess(struct garbagelist *oidwrlocked, int numoidwrlocked) {
781 /* Release read locks */
782 void ** dirwrlocked=oidwrlocked->array;
783 /* Release write locks */
784 for(i=numoidwrlocked-1; i>=0; i--) {
785 /* Read from the main heap */
786 header = &((objheader_t *)dirwrlocked[i])[-1];
787 write_unlock(&header->lock);
790 /* clear trec and then release objects locked */
791 struct objlist *ptr=lockedobjs;
794 for(i=max-1; i>=0; i--) {
795 header = (objheader_t *)ptr->objs[i];
797 pthread_mutex_unlock(header->objlock);
804 /* ==================================
807 * =================================
809 void transCommitProcess(struct garbagelist * oidwrlocked, int numoidwrlocked DELAYWRAP(, int numoidwrtotal, void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params)) {
813 struct objlist *ptr=newobjs;
814 void **dirwrlocked=oidwrlocked->array;
817 for(i=0; i<max; i++) {
819 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
824 /* Copy from transaction cache -> main object store */
825 for (i = numoidwrlocked-1; i >=0; i--) {
826 /* Read from the main heap */
827 header = &((objheader_t *)dirwrlocked[i])[-1];
829 GETSIZE(tmpsize, header);
830 struct ___Object___ *dst=(struct ___Object___*)dirwrlocked[i];
831 struct ___Object___ *src=t_chashSearch(dst);
832 dst->___cachedCode___=src->___cachedCode___;
833 dst->___cachedHash___=src->___cachedHash___;
834 A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
839 // call commit method
843 //splice oidwrlocked in
844 oidwrlocked->size=numoidwrtotal;
845 oidwrlocked->next=params;
846 ((struct garbagelist *)locals)->next=oidwrlocked;
847 commitmethod(params, locals, primitives);
848 ((struct garbagelist *)locals)->next=params;
851 /* Release write locks */
852 for(i=NUMWRTOTAL-1; i>=0; i--) {
853 header = &((objheader_t *)dirwrlocked[i])[-1];
855 write_unlock(&header->lock);
859 /* clear trec and then release objects locked */
863 for(i=max-1; i>=0; i--) {
864 header = (objheader_t *)ptr->objs[i];
866 pthread_mutex_unlock(header->objlock);