4 #define PERCENT_ALLOWED_ABORT 0.7
6 /* Thread variable for locking/unlocking */
7 __thread threadrec_t *trec;
8 __thread struct objlist * lockedobjs;
9 __thread int t_objnumcount=0;
11 /* Collect stats for object classes causing abort */
12 objtypestat_t typesCausingAbort[TOTALNUMCLASSANDARRAY];
14 void freelockedobjs() {
15 struct objlist *ptr=lockedobjs;
16 while(ptr->next!=NULL) {
17 struct objlist *tmp=ptr->next;
25 INLINE void getTransSize(objheader_t *header , int *isObjTypeTraverse) {
26 (typesCausingAbort[TYPE(header)]).numabort++;
27 if(isObjTypeTraverse[TYPE(header)] != 1) {
28 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
29 (typesCausingAbort[TYPE(header)]).numtrans+=1; //should this count be kept per object
31 isObjTypeTraverse[TYPE(header)]=1;
34 /*** Global variables *****/
35 objlockstate_t *objlockscope;
38 * params: object header
39 * Increments the abort count for each object
41 void ABORTCOUNT(objheader_t * x) {
42 int avgTransSize = typesCausingAbort[TYPE(x)].numaccess / typesCausingAbort[TYPE(x)].numtrans;
43 float transAbortProbForObj = (PERCENT_ALLOWED_ABORT*FACTOR)/(float) avgTransSize;
44 float ObjAbortProb = x->abortCount/(float) (x->accessCount);
45 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);
46 /* Condition for locking objects */
47 if (((ObjAbortProb*100) >= transAbortProbForObj) && (x->riskyflag != 1)) {
48 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);
49 //makes riskflag sticky
50 pthread_mutex_lock(&lockedobjstore);
51 if (objlockscope->offset<MAXOBJLIST) {
52 x->objlock=&(objlockscope->lock[objlockscope->offset++]);
54 objlockstate_t *tmp=malloc(sizeof(objlockstate_t));
55 tmp->next=objlockscope;
57 x->objlock=&(tmp->lock[0]);
60 pthread_mutex_unlock(&lockedobjstore);
61 pthread_mutex_init(x->objlock, NULL);
62 //should put a memory barrier here
68 #if defined(STMSTATS)||defined(SOFTABORT)
69 /** ========================================================================================
70 * getTotalAbortCount (for traverseCache only)
71 * params : start: start index of the loop
72 * : stop: stop index of the loop
73 * : startptr: pointer that points to where to start looking in the cache hash table
74 * : numoidrdlocked : number of objects read that are locked
75 * : oidrdlocked : array of objects read and currently locked
76 * : oidrdversion : array of versions of object read
77 * : oidrdage : array of ages of objects read ina transaction cache
78 * : ObjSeqId : sequence Id/age to start the comparision with
79 * =========================================================================================
81 int getTotalAbortCount(int start, int stop, void *startptr, int numoidrdlocked,
82 void *oidrdlocked, int *oidrdversion, int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
86 objheader_t *ObjToBeLocked=header;
87 chashlistnode_t *curr = (chashlistnode_t *) startptr;
88 chashlistnode_t *ptr = c_table;
89 /* First go through all objects left in the cache that have not been covered yet */
90 for(i = start; i < stop; i++) {
93 /* Inner loop to traverse the linked list of the cache lookupTable */
97 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
98 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
99 unsigned int version = headeraddr->version;
100 /* versions do not match */
101 if(version != header->version) {
103 header->abortCount++;
104 if(ObjSeqId > headeraddr->accessCount) {
105 ObjSeqId = headeraddr->accessCount;
106 ObjToBeLocked = header;
108 getTransSize(header, isObjTypeTraverse);
117 /* Then go through all objects that are read and are currently present in the readLockedArray */
118 if(numoidrdlocked>0) {
119 for(i=0; i<numoidrdlocked; i++) {
120 objheader_t *header = ((void **) oidrdlocked)[i];
121 int OidAge = oidrdage[i];
122 unsigned int version = oidrdversion[i];
123 if(version != header->version) { /* versions do not match */
125 header->abortCount++;
126 if(ObjSeqId > OidAge) {
128 ObjToBeLocked = header;
130 getTransSize(header, isObjTypeTraverse);
137 /* Acquire lock on the oldest object accessed in the transaction cache */
138 if(ObjToBeLocked != NULL) {
139 ABORTCOUNT(ObjToBeLocked);
145 /** ========================================================================================
146 * getTotalAbortCount2 (for alttraverseCache only)
147 * params : startptr: pointer that points to where to start looking in the cache hash table
148 * : numoidrdlocked : number of objects read that are locked
149 * : oidrdlocked : array of objects read and currently locked
150 * : oidrdversion : array of versions of object read
151 * : oidrdage : array of ages of objects read ina transaction cache
152 * : ObjSeqId : sequence Id/age to start the comparision with
153 * =========================================================================================
155 int getTotalAbortCount2(void *startptr, int numoidrdlocked, void *oidrdlocked,
156 int *oidrdversion, int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
158 chashlistnode_t *curr = (chashlistnode_t *) startptr;
159 objheader_t *ObjToBeLocked=header;
161 /* Inner loop to traverse the linked list of the cache lookupTable */
162 while(curr != NULL) {
163 objheader_t *headeraddr=&((objheader_t *) curr->val)[-1];
164 objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
165 unsigned int version = headeraddr->version;
166 /* versions do not match */
167 if(version != header->version) {
169 header->abortCount++;
170 if(ObjSeqId > headeraddr->accessCount) {
171 ObjSeqId = headeraddr->accessCount;
172 ObjToBeLocked = header;
174 getTransSize(header, isObjTypeTraverse);
181 /* Then go through all objects that are read and are currently present in the readLockedArray */
182 if(numoidrdlocked>0) {
184 for(i=0; i<numoidrdlocked; i++) {
185 objheader_t *header = ((void **)oidrdlocked)[i];
186 unsigned int version = oidrdversion[i];
187 int OidAge = oidrdage[i];
188 if(version != header->version) { /* versions do not match */
190 header->abortCount++;
191 if(ObjSeqId > OidAge) {
193 ObjToBeLocked = header;
195 getTransSize(header, isObjTypeTraverse);
202 if(ObjToBeLocked!=NULL) {
203 ABORTCOUNT(ObjToBeLocked);
210 * getReadAbortCount : Tells the number of aborts caused by objects that are read by
211 * visiting the read array
212 * params: int start, int stop are indexes to readLocked array
213 * void *oidrdlocked = readLocked array
214 * int *oidrdversion = version array
215 * : oidrdage : array of ages of objects read ina transaction cache
216 * : ObjSeqId : sequence Id/age to start the comparision with
218 int getReadAbortCount(int start, int stop, void *oidrdlocked, int *oidrdversion,
219 int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
222 objheader_t *ObjToBeLocked=header;
224 /* Go through oids read that are locked */
225 for(i = start; i < stop; i++) {
226 objheader_t *header = ((void **)oidrdlocked)[i];
227 unsigned int version = oidrdversion[i];
228 int OidAge = oidrdage[i];
229 if(version != header->version) { /* versions do not match */
231 header->abortCount++;
232 if(ObjSeqId > OidAge) {
234 ObjToBeLocked = header;
236 getTransSize(header, isObjTypeTraverse);
242 if(ObjToBeLocked != NULL) {
243 ABORTCOUNT(ObjToBeLocked);
252 * params: Object header, ptr to garbage collector
253 * Locks an object that causes aborts
255 objheader_t * needLock(objheader_t *header, void *gl) {
258 while((lockstatus = pthread_mutex_trylock(header->objlock))
259 && ((ptr = header->trec) == NULL)) { //retry
262 if(lockstatus==0) { //acquired lock
265 } else { //failed to get lock
269 //see if other thread is blocked
270 if(ptr->blocked == 1) {
271 //it might be block, so ignore lock and clear our blocked flag
276 INTPTR ptrarray[]={1, (INTPTR)gl, (INTPTR) header};
277 void *lockptr=header->objlock;
278 stopforgc((struct garbagelist *)ptrarray);
279 //grab lock and wait our turn
280 pthread_mutex_lock(lockptr);
282 header=(objheader_t *) ptrarray[2];
284 pthread_mutex_lock(header->objptr);
286 /* we have lock, so we are not blocked anymore */
292 //trec->blocked is zero now
294 /* Save the locked object */
295 if (lockedobjs->offset<MAXOBJLIST) {
296 lockedobjs->objs[lockedobjs->offset++]=header;
298 struct objlist *tmp=malloc(sizeof(struct objlist));
299 tmp->next=lockedobjs;
308 * Inline fuction to get Transaction size per object type for those
313 INLINE void getTransSize(objheader_t *header , int *isObjTypeTraverse) {
314 (typesCausingAbort[TYPE(header)]).numabort++;
315 if(isObjTypeTraverse[TYPE(header)] != 1)
316 (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
317 isObjTypeTraverse[TYPE(header)]=1;