1 /* ============================================================
3 * - single thread commit on local machine
4 * =============================================================
5 * Copyright (c) 2009, University of California, Irvine, USA.
9 * =============================================================
15 /* Thread transaction variables */
16 __thread objstr_t *t_cache;
17 __thread struct objlist * newobjs;
20 int numTransCommit = 0;
21 int numTransAbort = 0;
23 int nSoftAbortCommit = 0;
24 int nSoftAbortAbort = 0;
28 /* ==================================================
30 * This function starts up the transaction runtime.
31 * ==================================================
37 /* ======================================
39 * - create an object store of given size
40 * ======================================
42 objstr_t *objstrCreate(unsigned int size) {
44 if((tmp = calloc(1, (sizeof(objstr_t) + size))) == NULL) {
45 printf("%s() Calloc error at line %d, %s\n", __func__, __LINE__, __FILE__);
50 tmp->top = tmp + 1; //points to end of objstr_t structure!
54 //free entire list, starting at store
55 void objstrDelete(objstr_t *store) {
57 while (store != NULL) {
65 /* =================================================
67 * This function initializes things required in the
69 * =================================================
72 t_cache = objstrCreate(1048576);
73 t_chashCreate(CHASH_SIZE, CLOADFACTOR);
76 /* =======================================================
78 * This function creates objects in the transaction record
79 * =======================================================
81 objheader_t *transCreateObj(void * ptr, unsigned int size) {
82 objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
83 objheader_t *retval=&tmp[1];
84 tmp->lock=RW_LOCK_BIAS;
87 // don't insert into table
88 if (newobjs->offset<MAXOBJLIST) {
89 newobjs->objs[newobjs->offset++]=retval;
91 struct objlist *tmp=malloc(sizeof(struct objlist));
97 return retval; //want space after object header
100 /* This functions inserts randowm wait delays in the order of msec
101 * Mostly used when transaction commits retry*/
108 req.tv_nsec = (long)(t%4); //1-11 microsec
109 nanosleep(&req, NULL);
113 /* ==============================================
115 * - allocate space in an object store
116 * ==============================================
118 void *objstrAlloc(objstr_t **osptr, unsigned int size) {
121 objstr_t *store=*osptr;
127 if (OSFREE(store)>=size) {
132 if ((store=store->next)==NULL)
137 unsigned int newsize=size>DEFAULT_OBJ_STORE_SIZE?size:DEFAULT_OBJ_STORE_SIZE;
138 objstr_t *os=(objstr_t *)calloc(1,(sizeof(objstr_t) + newsize));
143 os->top=((char *)ptr)+size;
148 /* =============================================================
150 * -finds the objects either in main heap
151 * -copies the object into the transaction cache
152 * =============================================================
154 __attribute__((pure)) void *transRead(void * oid) {
155 unsigned int machinenumber;
156 objheader_t *tmp, *objheader;
157 objheader_t *objcopy;
160 //quick case for new objects
161 if (((struct ___Object___ *)oid)->___objstatus___ & NEW)
164 /* Read from the main heap */
166 objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
167 GETSIZE(size, header);
168 size += sizeof(objheader_t);
169 objcopy = (objheader_t *) objstrAlloc(&t_cache, size);
170 memcpy(objcopy, header, size);
171 /* Insert into cache's lookup table */
173 t_chashInsert((unsigned int)oid, &objcopy[1]);
178 struct objlist *ptr=newobjs;
179 while(ptr->next!=NULL) {
180 struct objlist *tmp=ptr->next;
188 /* ================================================================
190 * - This function initiates the transaction commit process
191 * - goes through the transaction cache and decides
193 * ================================================================
200 /* Look through all the objects in the transaction hash table */
201 int finalResponse = traverseCache();
202 if(finalResponse == TRANS_ABORT) {
210 objstrDelete(t_cache);
214 if(finalResponse == TRANS_COMMIT) {
222 objstrDelete(t_cache);
226 /* wait a random amount of time before retrying to commit transaction*/
227 if(finalResponse == TRANS_SOFT_ABORT) {
234 printf("Error: in %s() Unknown outcome", __func__);
240 /* ==================================================
242 * - goes through the transaction cache and
243 * - decides if a transaction should commit or abort
244 * ==================================================
246 int traverseCache() {
247 /* Create info to keep track of objects that can be locked */
248 int numoidrdlocked=0;
249 int numoidwrlocked=0;
250 unsigned int oidrdlocked[c_numelements];
251 unsigned int oidwrlocked[c_numelements];
254 chashlistnode_t *ptr = c_table;
255 /* Represents number of bins in the chash table */
256 unsigned int size = c_size;
257 for(i = 0; i<size; i++) {
258 chashlistnode_t *curr = &ptr[i];
259 /* Inner loop to traverse the linked list of the cache lookupTable */
260 while(curr != NULL) {
261 //if the first bin in hash table is empty
264 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
266 unsigned int version = headeraddr->version;
267 objheader_t *header=(objheader_t *) (((char *)curr->key)-sizeof(objheader_t));
269 if(STATUS(headeraddr) & DIRTY) {
270 /* Read from the main heap and compare versions */
271 if(write_trylock(&header->lock)) { //can aquire write lock
272 if (version == header->version) {/* versions match */
273 /* Keep track of objects locked */
274 oidwrlocked[numoidwrlocked++] = OID(header);
276 oidwrlocked[numoidwrlocked++] = OID(header);
277 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
280 } else { /* cannot aquire lock */
281 if(version == header->version) /* versions match */
284 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
289 /* Read from the main heap and compare versions */
290 if(read_trylock(&header->lock)) { //can further aquire read locks
291 if(version == header->version) {/* versions match */
292 oidrdlocked[numoidrdlocked++] = OID(header);
294 oidrdlocked[numoidrdlocked++] = OID(header);
295 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
298 } else { /* cannot aquire lock */
299 if(version == header->version)
302 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
312 /* Decide the final response */
314 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
315 return TRANS_SOFT_ABORT;
317 transCommitProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
322 /* ===========================================================================
324 * - increments counters that keep track of objects read, modified or locked
325 * - updates the oids locked and oids newly created
326 * ===========================================================================
330 /* ==================================
333 * =================================
335 int transAbortProcess(unsigned int *oidrdlocked, int *numoidrdlocked, unsigned int *oidwrlocked, int *numoidwrlocked) {
338 /* Release read locks */
339 for(i=0; i< *numoidrdlocked; i++) {
340 /* Read from the main heap */
341 header = (objheader_t *)(((char *)(oidrdlocked[i])) - sizeof(objheader_t));
342 read_unlock(&header->lock);
345 /* Release write locks */
346 for(i=0; i< *numoidwrlocked; i++) {
347 /* Read from the main heap */
348 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
349 write_unlock(&header->lock);
353 /* ==================================
356 * =================================
358 int transCommitProcess(unsigned int *oidrdlocked, int *numoidrdlocked,
359 unsigned int *oidwrlocked, int *numoidwrlocked) {
363 struct objlist *ptr=newobjs;
368 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
373 /* Copy from transaction cache -> main object store */
374 for (i = 0; i < *numoidwrlocked; i++) {
375 /* Read from the main heap */
376 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
378 GETSIZE(tmpsize, header);
379 struct ___Object___ *dst=(struct ___Object___*)oidwrlocked[i];
380 struct ___Object___ *src=t_chashSearch(oidwrlocked[i]);
381 dst->___cachedCode___=src->___cachedCode___;
382 dst->___cachedHash___=src->___cachedHash___;
383 memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
384 header->version += 1;
387 /* Release read locks */
388 for(i=0; i< *numoidrdlocked; i++) {
389 /* Read from the main heap */
390 header = (objheader_t *)(((char *)(oidrdlocked[i])) - sizeof(objheader_t));
391 read_unlock(&header->lock);
394 /* Release write locks */
395 for(i=0; i< *numoidwrlocked; i++) {
396 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
397 write_unlock(&header->lock);