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 objheader_t *tmp, *objheader;
156 objheader_t *objcopy;
159 //quick case for new objects
160 if (((struct ___Object___ *)oid)->___objstatus___ & NEW)
163 /* Read from the main heap */
165 objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
166 GETSIZE(size, header);
167 size += sizeof(objheader_t);
168 objcopy = (objheader_t *) objstrAlloc(&t_cache, size);
169 memcpy(objcopy, header, size);
170 /* Insert into cache's lookup table */
172 t_chashInsert(oid, &objcopy[1]);
177 struct objlist *ptr=newobjs;
178 while(ptr->next!=NULL) {
179 struct objlist *tmp=ptr->next;
187 /* ================================================================
189 * - This function initiates the transaction commit process
190 * - goes through the transaction cache and decides
192 * ================================================================
199 /* Look through all the objects in the transaction hash table */
200 int finalResponse = traverseCache();
201 if(finalResponse == TRANS_ABORT) {
209 objstrDelete(t_cache);
214 if(finalResponse == TRANS_COMMIT) {
222 objstrDelete(t_cache);
227 /* wait a random amount of time before retrying to commit transaction*/
228 if(finalResponse == TRANS_SOFT_ABORT) {
235 printf("Error: in %s() Unknown outcome", __func__);
241 /* ==================================================
243 * - goes through the transaction cache and
244 * - decides if a transaction should commit or abort
245 * ==================================================
247 int traverseCache() {
248 /* Create info to keep track of objects that can be locked */
249 int numoidrdlocked=0;
250 int numoidwrlocked=0;
251 void * oidrdlocked[c_numelements];
252 void * oidwrlocked[c_numelements];
255 chashlistnode_t *ptr = c_table;
256 /* Represents number of bins in the chash table */
257 unsigned int size = c_size;
258 for(i = 0; i<size; i++) {
259 chashlistnode_t *curr = &ptr[i];
260 /* Inner loop to traverse the linked list of the cache lookupTable */
261 while(curr != NULL) {
262 //if the first bin in hash table is empty
263 if(curr->key == NULL)
265 objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
267 unsigned int version = headeraddr->version;
268 objheader_t *header=(objheader_t *) (((char *)curr->key)-sizeof(objheader_t));
270 if(STATUS(headeraddr) & DIRTY) {
271 /* Read from the main heap and compare versions */
272 if(write_trylock(&header->lock)) { //can aquire write lock
273 if (version == header->version) {/* versions match */
274 /* Keep track of objects locked */
275 oidwrlocked[numoidwrlocked++] = OID(header);
277 oidwrlocked[numoidwrlocked++] = OID(header);
278 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
281 } else { /* cannot aquire lock */
282 if(version == header->version) /* versions match */
285 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
290 /* Read from the main heap and compare versions */
291 if(read_trylock(&header->lock)) { //can further aquire read locks
292 if(version == header->version) {/* versions match */
293 oidrdlocked[numoidrdlocked++] = OID(header);
295 oidrdlocked[numoidrdlocked++] = OID(header);
296 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
299 } else { /* cannot aquire lock */
300 if(version == header->version)
303 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
313 /* Decide the final response */
315 transAbortProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
316 return TRANS_SOFT_ABORT;
318 transCommitProcess(oidrdlocked, &numoidrdlocked, oidwrlocked, &numoidwrlocked);
324 /* ==================================
327 * =================================
329 int transAbortProcess(void **oidrdlocked, int *numoidrdlocked, void **oidwrlocked, int *numoidwrlocked) {
332 /* Release read locks */
333 for(i=0; i< *numoidrdlocked; i++) {
334 /* Read from the main heap */
335 header = (objheader_t *)(((char *)(oidrdlocked[i])) - sizeof(objheader_t));
336 read_unlock(&header->lock);
339 /* Release write locks */
340 for(i=0; i< *numoidwrlocked; i++) {
341 /* Read from the main heap */
342 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
343 write_unlock(&header->lock);
347 /* ==================================
350 * =================================
352 int transCommitProcess(void ** oidrdlocked, int *numoidrdlocked,
353 void ** oidwrlocked, int *numoidwrlocked) {
357 struct objlist *ptr=newobjs;
362 ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
367 /* Copy from transaction cache -> main object store */
368 for (i = 0; i < *numoidwrlocked; i++) {
369 /* Read from the main heap */
370 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
372 GETSIZE(tmpsize, header);
373 struct ___Object___ *dst=(struct ___Object___*)oidwrlocked[i];
374 struct ___Object___ *src=t_chashSearch(oidwrlocked[i]);
375 dst->___cachedCode___=src->___cachedCode___;
376 dst->___cachedHash___=src->___cachedHash___;
377 memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
378 header->version += 1;
381 /* Release read locks */
382 for(i=0; i< *numoidrdlocked; i++) {
383 /* Read from the main heap */
384 header = (objheader_t *)(((char *)(oidrdlocked[i])) - sizeof(objheader_t));
385 read_unlock(&header->lock);
388 /* Release write locks */
389 for(i=0; i< *numoidwrlocked; i++) {
390 header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
391 write_unlock(&header->lock);