1 #include "hashStructure.h"
2 #include "WaitingQueue.h"
6 //NOTE: this is only temporary (for testing) and will be removed in favor of thread local variables
7 //It's basically an array of hashStructures so we can simulate what would happen in a many-threaded version
8 HashStructure ** allHashStructures;
10 //NOTE: only temporary
11 void rcr_createMasterHashTableArray(int maxSize){
14 HashStructure* rcr_createHashtable(int sizeofWaitingQueue){
16 HashStructure* newTable=(HashStructure*)RUNMALLOC(sizeof(HashStructure));
17 for(i=0;i<NUMBINS;i++){
18 newTable->array[i].head=NULL;
19 newTable->array[i].tail=NULL;
22 newTable->waitingQueue=mallocWaitingQueue(sizeofWaitingQueue);
26 WriteBinItem_rcr* rcr_createWriteBinItem(){
27 WriteBinItem_rcr* binitem=(WriteBinItem_rcr*)RUNMALLOC(sizeof(WriteBinItem_rcr));
28 binitem->item.type=WRITEBIN;
32 ReadBinItem_rcr* rcr_createReadBinItem(){
33 ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)RUNMALLOC(sizeof(ReadBinItem_rcr));
35 binitem->item.type=READBIN;
39 int rcr_isReadBinItem(BinItem_rcr* b){
40 return b->type==READBIN;
43 int rcr_isWriteBinItem(BinItem_rcr* b){
44 return b->type==WRITEBIN;
47 inline int rcr_generateKey(void * ptr){
48 return (((struct genericObjectStruct *) ptr)->oid)&H_MASK;
51 //TODO handle logic for waiting Queues separately
52 //TODO pass in task to traverser
53 int rcr_ADDTABLEITEM(HashStructure* table, void * ptr, int type, int traverserID, SESEcommon *task, void * heaproot){
55 int key=rcr_generateKey(ptr);
57 //LOCK is still needed as different threads will remove items...
59 val=(BinItem_rcr *)0x1;
60 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(table->array[key].head), (unsigned INTPTR)val);
61 } while(val==(BinItem_rcr*)0x1);
64 return rcr_EMPTYBINCASE(table, &table->array[key], ptr, type, traverserID, task, heaproot);
67 if (type == WRITEEFFECT) {
68 return rcr_WRITEBINCASE(table, val, ptr, key, traverserID, task, heaproot);
69 } else if (type == READEFFECT) {
70 return rcr_READBINCASE(table, val, ptr, key, traverserID, task, heaproot);
75 int rcr_EMPTYBINCASE(HashStructure *T, BinElement_rcr* be, void *ptr, int type, int traverserId, SESEcommon * task, void *heaproot){
78 //TODO: NEED PARENT CHECK HERE!!!!!!!!!
81 if (type == WRITEEFFECT) {
82 b=(BinItem_rcr*)rcr_createWriteBinItem();
83 td = &((WriteBinItem_rcr*)b)->val;
84 } else if (type == READEFFECT) {
85 b=(BinItem_rcr*)rcr_createReadBinItem();
86 ReadBinItem_rcr* readbin=(ReadBinItem_rcr*)b;
87 td = &(readbin->array[readbin->index++]);
93 //common to both types
98 td->traverserID = traverserId;
99 td->heaproot = heaproot;
109 int rcr_WRITEBINCASE(HashStructure *T, BinItem_rcr *val, void *ptr, int key, int traverserID, SESEcommon *task, void *heaproot) {
110 //chain of bins exists => tail is valid
111 //if there is something in front of us, then we are not ready
113 BinElement_rcr* be= &(T->array[key]); //do not grab head from here since it's locked (i.e. = 0x1)
114 BinItem_rcr *bintail=be->tail;
116 if (bintail->type == WRITEBIN) {
117 TraverserData * td = &(((WriteBinItem_rcr *)bintail)->val);
118 //last one is to check for SESE blocks in a while loop.
119 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID && td->task == task) {
120 return bintail->status;
122 } else if (bintail->type == READBIN) {
123 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
124 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
125 //if it matches, then we remove it and the code below will upgrade it to a write.
126 ((ReadBinItem_rcr *)bintail)->index--;
131 WriteBinItem_rcr *b=rcr_createWriteBinItem();
132 TraverserData * td = &b->val;
135 //fillout traverserData
136 //Note: this list could be smaller in the future, for now I'm just including all the info I may need.
137 td->binitem = (BinItem_rcr*)b;
141 td->traverserID = traverserID;
142 td->heaproot = heaproot;
144 b->item.status=status;
145 bintail->next=(BinItem_rcr*)b;
146 be->tail=(BinItem_rcr*)b;
152 int rcr_READBINCASE(HashStructure *T, BinItem_rcr *val, void *ptr, int key, int traverserID, SESEcommon * task, void *heaproot) {
153 BinElement_rcr * be = &(T->array[key]);
154 BinItem_rcr * bintail=be->tail;
155 //check if already added item or not.
156 if (bintail->type == WRITEBIN) {
157 TraverserData * td = &(((WriteBinItem_rcr *)bintail)->val);
158 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
161 return bintail->status;
163 } else if (bintail->type == READEFFECT) {
164 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
165 if (unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
168 return bintail->status;
172 if (isReadBinItem(bintail)) {
173 return rcr_TAILREADCASE(T, ptr, val, bintail, key, traverserID, task, heaproot);
174 } else if (!isReadBinItem(bintail)) {
175 rcr_TAILWRITECASE(T, ptr, val, bintail, key, traverserID, task, heaproot);
181 int rcr_TAILREADCASE(HashStructure *T, void * ptr, BinItem_rcr *val, BinItem_rcr *bintail, int key, int traverserID, SESEcommon * task, void *heaproot) {
182 ReadBinItem_rcr * readbintail=(ReadBinItem_rcr*)T->array[key].tail;
185 if (readbintail->item.status==READY) {
193 if (readbintail->index==NUMREAD) { // create new read group
194 ReadBinItem_rcr* rb=rcr_createReadBinItem();
195 td = &rb->array[rb->index++];
198 rb->item.status=status;
199 T->array[key].tail->next=(BinItem_rcr*)rb;
200 T->array[key].tail=(BinItem_rcr*)rb;
201 } else { // group into old tail
202 td = &readbintail->array[readbintail->index++];
203 atomic_inc(&readbintail->item.total);
204 //printf("grouping with %d\n",readbintail->index);
207 td->binitem = bintail;
211 td->traverserID = traverserID;
212 td->heaproot = heaproot;
214 T->array[key].head=val;//released lock
218 void rcr_TAILWRITECASE(HashStructure *T, void *ptr, BinItem_rcr *val, BinItem_rcr *bintail, int key, int traverserID, SESEcommon * task, void *heaproot) {
219 ReadBinItem_rcr* rb=rcr_createReadBinItem();
220 TraverserData * td = &(rb->array[rb->index++]);
222 rb->item.status=NOTREADY;
224 td->binitem = (BinItem_rcr *) rb;
228 td->traverserID = traverserID;
229 td->heaproot = heaproot;
231 T->array[key].tail->next=(BinItem_rcr*)rb;
232 T->array[key].tail=(BinItem_rcr*)rb;
233 T->array[key].head=val;//released lock
236 //TODO write deletion/removal methods
239 RETIREHASHTABLE(MemoryQueue *q, REntry *r) {
240 Hashtable *T=r->hashtable;
241 BinItem_rcr *b=r->binitem;
245 RETIREBIN(Hashtable *T, REntry *r, BinItem_rcr *b) {
246 int key=generateKey( OBJPTRPTR_2_OBJOID( r->pointer ) );
248 atomic_dec(&b->total);
250 if (isFineWrite(r) || (isFineRead(r) && b->next!=NULL && b->total==0)) {
251 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
254 val=(BinItem_rcr*)0x1;
255 val=(BinItem_rcr*)LOCKXCHG((unsigned INTPTR*)&(T->array[key]->head), (unsigned INTPTR)val);
256 } while(val==(BinItem_rcr*)0x1);
257 // at this point have locked bin
258 BinItem_rcr *ptr=val;
262 if (isReadBinItem(ptr)) {
263 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)ptr;
264 if (rptr->item.status==NOTREADY) {
265 for (i=0;i<rptr->index;i++) {
266 resolveDependencies(rptr->array[i]);
267 if (isParent(rptr->array[i])) {
268 //parents go immediately
269 atomic_dec(&rptr->item.total);
270 atomic_dec(&T->item.total);
274 rptr->item.status=READY;
275 if (rptr->item.next==NULL) {
278 if (rptr->item.total!=0) {
280 } else if ((BinItem_rcr*)rptr==val) {
283 } else if(isWriteBinItem(ptr)) {
286 if(ptr->status==NOTREADY){
287 resolveDependencies(((WriteBinItem_rcr*)ptr)->val);
289 if(isParent(((WriteBinItem_rcr*)ptr)->val)){
290 atomic_dec(&T->item.total);
294 }else{ // write bin is already resolved
300 T->array[key]->head=val; // release lock
306 //Int will return success/fail. -1 indicates error (i.e. there's nothing there).
307 //0 = nothing removed, >0 something was removed
308 int REMOVETABLEITEM(HashStructure* table, void * ptr, int traverserID, SESEcommon *task, void * heaproot) {
309 int key = generateKey(ptr);
310 BinElement_rcr * bucket = table->array[key];
312 if(bucket->head == NULL) {
314 //This can occur if we try to remove something that's in the waitingQueue directly from the hashtable.
317 if(bucket->head->type == WRITEBIN) {
318 TraverserData * td = &(((WriteBinItem_rcr *) head)->val);
319 if(td->resumePtr == ptr && td->traverserID == traverserID && td->heaproot == heaproot) {
320 BinItem_rcr * temp = bucket->head;
321 bucket->head = bucket->head->next;
322 free(temp); //TODO perhaps implement a linked list of free BinElements as was done in WaitingQueue
324 //Handle items behind write item
325 if(bucket->head == NULL) {
326 bucket->tail == NULL;
330 int type = bucket->head->type;
331 switch(bucket->head->type) {
333 bucket->head->status = READY;
334 //TODO Decrement dependency count
336 case WAITINGQUEUENOTE:
337 int retval = removeFromWaitingQueue(table->waitingQueue, ((WaitingQueueNote *) bucket->head)->allocSiteID, traverserID);
339 //we set both to NULL because the note should ALWAYS be the last item in the hashStructure.
345 BinItem_rcr * temp = bucket->head;
346 while(temp != NULL && temp->type == READBIN) {
347 temp->status = READY;
349 //TODO decrement dependency count
358 if(bucket->head->type == READBIN) {
359 //TODO There's an issue here; bins are groups of items that may be enqueued by different ids.
360 //I may have to search through them to find which one to remove but then there'd be a blank spot in an
361 //otherwise clean array. It wouldn't make sense to just check the first one since reads are reorderable.
362 //Nor does it make sense to lop off the reads since that may signal the next write to be ready even before it
366 if(bucket->head->type == WAITINGQUEUENOTE) {
367 int retval = removeFromWaitingQueue(table->waitingQueue, ((WaitingQueueNote *) bucket->head)->allocSiteID, traverserID);