bug fixes in manual prefetch for LookService benchmark
[IRC.git] / Robust / src / Runtime / DSTM / interface / prefetch.c
1 #include "prefetch.h"
2 #include "prelookup.h"
3 #include "sockpool.h"
4 #include "gCollect.h"
5
6 extern sockPoolHashTable_t *transPrefetchSockPool;
7 extern unsigned int myIpAddr;
8 extern sockPoolHashTable_t *transPResponseSocketPool;
9 extern pthread_mutex_t prefetchcache_mutex;
10 extern prehashtable_t pflookup;
11
12 // Function for new prefetch call
13 void rangePrefetch(unsigned int oid, short numoffset, short *offsets) {
14   /* Allocate memory in prefetch queue and push the block there */
15   int qnodesize = sizeof(unsigned int) + sizeof(unsigned short) + numoffset * sizeof(short);
16   char *node = (char *) getmemory(qnodesize);
17
18   if(node == NULL)
19     return;
20
21   int index = 0;
22   ((unsigned int *)node)[0] = oid;
23   index = index + (sizeof(unsigned int));
24   *((short *)(node+index)) = numoffset;
25   index = index + (sizeof(short));
26   memcpy(node+index, offsets, numoffset * sizeof(short));
27
28   movehead(qnodesize);
29 }
30
31 void *transPrefetchNew() {
32   while(1) {
33     /* Read from prefetch queue */
34     void *node = gettail();
35
36     /* Check tuples if they are found locally */
37     perMcPrefetchList_t* pilehead = checkIfLocal(node);
38
39     if (pilehead!=NULL) {
40       // Get sock from shared pool
41       int sd = getSock2(transPrefetchSockPool, pilehead->mid);
42
43       /* Send  Prefetch Request */
44       perMcPrefetchList_t *ptr = pilehead;
45       while(ptr != NULL) {
46         sendRangePrefetchReq(ptr, sd);
47         ptr = ptr->next;
48       }
49
50       /* Deallocated pilehead */
51       proPrefetchQDealloc(pilehead);
52     }
53     // Deallocate the prefetch queue pile node
54     inctail();
55   }
56 }
57
58 int getsize(short *ptr, int n) {
59   int sum = 0, newsum, i;
60   for (i = n-1; i >= 0; i--) {
61     newsum = (1 + ptr[i])+((1 + ptr[i])*sum);
62     sum = newsum;
63   }
64   return sum;
65 }
66
67
68 perMcPrefetchList_t *checkIfLocal(char *ptr) {
69   unsigned int oid = *(GET_OID(ptr));
70   short numoffset = *(GET_NUM_OFFSETS(ptr));
71   short *offsetarray = GET_OFFSETS(ptr);
72   int depth=0, top=0;
73   unsigned int dfsList[numoffset];
74   oidAtDepth_t odep;
75
76   /* Initialize */
77   perMcPrefetchList_t *head = NULL;
78   odep.oid = 0;
79   odep.depth = 0;
80   int i;
81   for(i = 0; i<numoffset; i++) {
82     dfsList[i] = 0;
83   }
84
85   //Start searching the dfsList
86   while(top >= 0) {
87     int retval;
88     if((retval = getNextOid(offsetarray, dfsList, &top, &depth, &odep, oid)) != 0) {
89       printf("%s() Error: Getting new oid at %s, %d\n", __func__, __FILE__, __LINE__);
90       return NULL;
91     }
92     dfsList[top] = odep.oid;
93     dfsList[top+1] = 0;
94 labelL1:
95     ;
96     objheader_t *objhead = searchObj(dfsList[top]);
97     if(objhead == NULL) { //oid not found
98       if(dfsList[top] == 0) { //oid is null
99         ;
100       } else {
101         // Not found
102         int machinenum = lhashSearch(dfsList[top]);
103         insertPrefetch(machinenum, dfsList[top], numoffset-(depth), &offsetarray[depth], &head);
104       }
105       //go up the tree
106       while((dfsList[top+1] == *(offsetarray + depth + 1)) && (depth >= 0)) {
107         if(top == depth) {
108           top -= 2;
109           depth -= 2;
110         } else {
111           depth -= 2;
112         }
113       }
114       //return if no more paths to explore
115       if(top < 0 || depth < 0) {
116         return head;
117       }
118       //If more paths to explore, proceed down the tree
119       dfsList[top+1]++;
120       int prev = top - 2;
121       objheader_t *header;
122       header = searchObj(dfsList[prev]);
123       if(header == NULL) {
124         printf("%s() Error Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
125         return NULL;
126       } else {
127         //if Array
128         if(TYPE(header) > NUMCLASSES) {
129           dfsList[top] = getNextArrayOid(offsetarray, dfsList, &top, &depth);
130         } else { //linked list
131           dfsList[top] = getNextPointerOid(offsetarray, dfsList, &top, &depth);
132         }
133         goto labelL1;
134       }
135     } else { // increment and go down the tree
136       //Increment top
137       top += 2;
138       depth += 2;
139       if(depth >= numoffset) { //reached the end of the path
140         top -= 2;
141         depth -= 2;
142         //go up the tree
143         while((dfsList[top + 1] == *(offsetarray + depth + 1)) && (depth >= 0)) {
144           if(top == depth) {
145             top -= 2;
146             depth -= 2;
147           } else
148             depth -= 2;
149         }
150         //return if no more paths to explore
151         if(top < 0 || depth < 0) {
152           return head;
153         }
154         //If more paths to explore, go down the tree
155         dfsList[top + 1]++;
156         int prev = top - 2;
157         objheader_t * header;
158         header = searchObj(dfsList[prev]);
159         if(header == NULL) {
160           printf("%s() Error Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
161           return NULL;
162         } else {
163           //if Array
164           if(TYPE(header) > NUMCLASSES) {
165             dfsList[top] = getNextArrayOid(offsetarray, dfsList, &top, &depth);
166           } else { //linked list
167             dfsList[top] = getNextPointerOid(offsetarray, dfsList, &top, &depth);
168           }
169           goto labelL1;
170         }
171       } else
172         continue;
173     }
174   } //end of while
175   return head;
176 }
177
178 objheader_t *searchObj(unsigned int oid) {
179   objheader_t *header = NULL;
180
181   if ((header = (objheader_t *)mhashSearch(oid)) != NULL) {
182     return header;
183   } else if ((header = (objheader_t *) prehashSearch(oid)) != NULL) {
184     return header;
185   } else {
186     //printf("Error: Cannot find header %s, %d\n", __func__, __LINE__);
187   }
188   return NULL;
189 }
190
191 /* Delete perMcPrefetchList_t and everything it points to */
192 void proPrefetchQDealloc(perMcPrefetchList_t *node) {
193   perMcPrefetchList_t *prefetchpile_ptr;
194   perMcPrefetchList_t *prefetchpile_next_ptr;
195   objOffsetPile_t *objpile_ptr;
196   objOffsetPile_t *objpile_next_ptr;
197
198   prefetchpile_ptr = node;
199   while (prefetchpile_ptr != NULL) {
200     prefetchpile_next_ptr = prefetchpile_ptr;
201     while(prefetchpile_ptr->list != NULL) {
202       //offsets aren't owned by us, so we don't free them.
203       objpile_ptr = prefetchpile_ptr->list;
204       prefetchpile_ptr->list = objpile_ptr->next;
205       free(objpile_ptr);
206     }
207     prefetchpile_ptr = prefetchpile_next_ptr->next;
208     free(prefetchpile_next_ptr);
209   }
210 }
211
212 void insertPrefetch(int mid, unsigned int oid, short numoffset, short *offsets, perMcPrefetchList_t **head) {
213   perMcPrefetchList_t *ptr;
214   objOffsetPile_t *objnode;
215   objOffsetPile_t **tmp;
216
217   //Loop through the machines
218   for(; 1; head=&((*head)->next)) {
219     int tmid;
220     if ((*head)==NULL||(tmid=(*head)->mid)>mid) {
221       perMcPrefetchList_t * tmp = (perMcPrefetchList_t *) malloc(sizeof(perMcPrefetchList_t));
222       tmp->mid = mid;
223       objnode =  malloc(sizeof(objOffsetPile_t));
224       objnode->offsets = offsets;
225       objnode->oid = oid;
226       objnode->numoffset = numoffset;
227       objnode->next = NULL;
228       tmp->list = objnode;
229       tmp->next = *head;
230       *head=tmp;
231       return;
232     }
233
234     //keep looking
235     if (tmid < mid)
236       continue;
237
238     //found mid list
239     for(tmp=&((*head)->list); 1; tmp=&((*tmp)->next)) {
240       int toid;
241       int matchstatus;
242
243       if ((*tmp)==NULL||((toid=(*tmp)->oid)>oid)) {
244         objnode = (objOffsetPile_t *) malloc(sizeof(objOffsetPile_t));
245         objnode->offsets = offsets;
246         objnode->oid = oid;
247         objnode->numoffset = numoffset;
248         objnode->next = *tmp;
249         *tmp = objnode;
250         return;
251       }
252       if (toid < oid)
253         continue;
254
255       /* Fill list DS */
256       int i;
257       int onumoffset=(*tmp)->numoffset;
258       short * ooffset=(*tmp)->offsets;
259
260       for(i=0; i<numoffset; i++) {
261         if (i>onumoffset) {
262           //We've matched, let's just extend the current prefetch
263           (*tmp)->numoffset=numoffset;
264           (*tmp)->offsets=offsets;
265           return;
266         }
267         if (ooffset[i]<offsets[i]) {
268           goto oidloop;
269         } else if (ooffset[i]>offsets[i]) {
270           //Place item before the current one
271           objnode = (objOffsetPile_t *) malloc(sizeof(objOffsetPile_t));
272           objnode->offsets = offsets;
273           objnode->oid = oid;
274           objnode->numoffset = numoffset;
275           objnode->next = *tmp;
276           *tmp = objnode;
277           return;
278         }
279       }
280       //if we get to the end, we're already covered by this prefetch
281       return;
282 oidloop:
283       ;
284     }
285   }
286 }
287
288 void sendRangePrefetchReq(perMcPrefetchList_t *mcpilenode, int sd) {
289   int len, endpair;
290   char control;
291   objOffsetPile_t *tmp;
292
293   /* Send TRANS_PREFETCH control message */
294   control = TRANS_PREFETCH;
295   send_data(sd, &control, sizeof(char));
296
297   /* Send Oids and offsets in pairs */
298   tmp = mcpilenode->list;
299   while(tmp != NULL) {
300     len = sizeof(int) + sizeof(unsigned int) + sizeof(unsigned int) + ((tmp->numoffset) * sizeof(short));
301     char oidnoffset[len];
302     char *buf=oidnoffset;
303     *((int*)buf) = tmp->numoffset;
304     buf+=sizeof(int);
305     *((unsigned int *)buf) = tmp->oid;
306     buf+=sizeof(unsigned int);
307     *((unsigned int *)buf) = myIpAddr;
308     buf += sizeof(unsigned int);
309     memcpy(buf, tmp->offsets, (tmp->numoffset)*sizeof(short));
310     send_data(sd, oidnoffset, len);
311     tmp = tmp->next;
312   }
313
314   /* Send a special char -1 to represent the end of sending oids + offset pair to remote machine */
315   endpair = -1;
316   send_data(sd, &endpair, sizeof(int));
317   return;
318 }
319
320 int getRangePrefetchResponse(int sd) {
321   int length = 0;
322   recv_data(sd, &length, sizeof(int));
323   int size = length - sizeof(int);
324   char recvbuffer[size];
325   recv_data(sd, recvbuffer, size);
326   char control = *((char *) recvbuffer);
327   unsigned int oid;
328   if(control == OBJECT_FOUND) {
329     oid = *((unsigned int *)(recvbuffer + sizeof(char)));
330     size = size - (sizeof(char) + sizeof(unsigned int));
331     pthread_mutex_lock(&prefetchcache_mutex);
332     void *ptr;
333     if((ptr = prefetchobjstrAlloc(size)) == NULL) {
334       printf("%s() Error: objstrAlloc error for copying into prefetch cache in line %d at %s\n",
335              __func__, __LINE__, __FILE__);
336       pthread_mutex_unlock(&prefetchcache_mutex);
337       return -1;
338     }
339     pthread_mutex_unlock(&prefetchcache_mutex);
340     memcpy(ptr, recvbuffer + sizeof(char) + sizeof(unsigned int), size);
341     STATUS(ptr)=0;
342
343     /* Insert into prefetch hash lookup table */
344     void * oldptr;
345     if((oldptr = prehashSearch(oid)) != NULL) {
346       if(((objheader_t *)oldptr)->version <= ((objheader_t *)ptr)->version) {
347         prehashRemove(oid);
348         prehashInsert(oid, ptr);
349       }
350     } else {
351       prehashInsert(oid, ptr);
352     }
353     pthread_mutex_lock(&pflookup.lock);
354     pthread_cond_broadcast(&pflookup.cond);
355     pthread_mutex_unlock(&pflookup.lock);
356   } else if(control == OBJECT_NOT_FOUND) {
357     oid = *((unsigned int *)(recvbuffer + sizeof(char)));
358     //printf("%s() Error: OBJ NOT FOUND.. THIS SHOULD NOT HAPPEN\n", __func__);
359   } else {
360     printf("%s() Error: in Decoding the control value %d, %s\n", __func__, __LINE__, __FILE__);
361   }
362   return 0;
363 }
364
365 int rangePrefetchReq(int acceptfd) {
366   int numoffset, sd = -1;
367   unsigned int baseoid, mid = -1;
368   oidmidpair_t oidmid;
369
370   while (1) {
371     recv_data(acceptfd, &numoffset, sizeof(int));
372     if(numoffset == -1)
373       break;
374     recv_data(acceptfd, &oidmid, 2*sizeof(unsigned int));
375     baseoid = oidmid.oid;
376     if(mid != oidmid.mid) {
377       if(mid!= -1)
378         freeSockWithLock(transPResponseSocketPool, mid, sd);
379       mid = oidmid.mid;
380       sd = getSockWithLock(transPResponseSocketPool, mid);
381     }
382     short offsetsarry[numoffset];
383     recv_data(acceptfd, offsetsarry, numoffset*sizeof(short));
384
385     int retval;
386     if((retval = dfsOffsetTree(baseoid, offsetsarry, sd, numoffset)) != 0) {
387       printf("%s() Error: in dfsOffsetTree() at line %d in %s()\n",
388              __func__, __LINE__, __FILE__);
389       return -1;
390     }
391   }
392
393   //Release socket
394   if(mid!=-1)
395     freeSockWithLock(transPResponseSocketPool, mid, sd);
396   return 0;
397 }
398
399 int dfsOffsetTree(unsigned int baseoid, short * offsetarray, int sd, int numoffset) {
400   int depth=0, top=0;
401   unsigned int dfsList[numoffset];
402   oidAtDepth_t odep;
403
404   /* Initialize */
405   odep.oid = 0;
406   odep.depth = 0;
407   int i;
408   for(i = 0; i<numoffset; i++) {
409     dfsList[i] = 0;
410   }
411
412   //Start searching the dfsList
413   while(top >= 0) {
414     int retval;
415     if((retval = getNextOid(offsetarray, dfsList, &top, &depth, &odep, baseoid)) != 0) {
416       printf("%s() Error: Getting new oid at %s, %d\n", __func__, __FILE__, __LINE__);
417       return -1;
418     }
419     dfsList[top] = odep.oid;
420     dfsList[top+1] = 0;
421 labelL1:
422     ;
423     objheader_t *objhead = searchObj(dfsList[top]);
424     if(objhead == NULL) { //null oid or oid not found
425       int retval;
426       if((retval = sendOidNotFound(dfsList[top], sd)) != 0) {
427         printf("%s() Error in sendOidNotFound() at line %d in %s()\n", __func__, __LINE__, __FILE__);
428         return -1;
429       }
430       //go up the tree
431       while((dfsList[top+1] == *(offsetarray + depth + 1)) && (depth >= 0)) {
432         if(top == depth) {
433           top -= 2;
434           depth -= 2;
435         } else {
436           depth -= 2;
437         }
438       }
439       //return if no more paths to explore
440       if(top < 0 || depth < 0) {
441         return 0;
442       }
443       //If more paths to explore, proceed down the tree
444       dfsList[top+1]++;
445       int prev = top - 2;
446       objheader_t *header;
447       header = searchObj(dfsList[prev]);
448       if(header == NULL) {
449         printf("%s() Error Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
450         return -1;
451         //return 0;
452       } else {
453         //if Array
454         if(TYPE(header) > NUMCLASSES) {
455           dfsList[top] = getNextArrayOid(offsetarray, dfsList, &top, &depth);
456         } else { //linked list
457           dfsList[top] = getNextPointerOid(offsetarray, dfsList, &top, &depth);
458         }
459         goto labelL1;
460       }
461     } else { // increment and go down the tree
462       //Send Object id found
463       if((retval = sendOidFound(OID(objhead), sd)) != 0) {
464         printf("%s() Error in sendOidFound() at line %d in %s()\n", __func__, __LINE__, __FILE__);
465         return -1;
466       }
467       //Increment top
468       top += 2;
469       depth += 2;
470       if(depth >= numoffset) { //reached the end of the path
471         top -= 2;
472         depth -= 2;
473         //go up the tree
474         while((dfsList[top + 1] == *(offsetarray + depth + 1)) && (depth >= 0)) {
475           if(top == depth) {
476             top -= 2;
477             depth -= 2;
478           } else
479             depth -= 2;
480         }
481         //return if no more paths to explore
482         if(top < 0 || depth < 0) {
483           return 0;
484         }
485         //If more paths to explore, go down the tree
486         dfsList[top + 1]++;
487         int prev = top - 2;
488         objheader_t * header;
489         header = searchObj(dfsList[prev]);
490         if(header == NULL) {
491           printf("%s() Error Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
492           return -1;
493           //return 0;
494         } else {
495           //if Array
496           if(TYPE(header) > NUMCLASSES) {
497             dfsList[top] = getNextArrayOid(offsetarray, dfsList, &top, &depth);
498           } else { //linked list
499             dfsList[top] = getNextPointerOid(offsetarray, dfsList, &top, &depth);
500           }
501           goto labelL1;
502         }
503       } else
504         continue;
505     }
506   } //end of while
507   return 0;
508 }
509
510 int getNextOid(short * offsetarray, unsigned int *dfsList, int *top, int *depth, oidAtDepth_t *odep, unsigned int baseoid) {
511   if(*top == 0) {
512     odep->oid = baseoid;
513     odep->depth = 0;
514   } else {
515     int prev = (*top) - 2;
516     unsigned int oid = *(dfsList+prev);
517     objheader_t * header = searchObj(oid);
518     if(header == NULL) {
519       odep->oid = 0;
520       odep->depth = 0;
521       return 0;
522     } else {
523       int range = GET_RANGE(*(offsetarray+(*depth) + 1));
524       short stride = GET_STRIDE(*(offsetarray+(*depth) + 1));
525       stride++; //Note bit pattern 000 => stride = 1 etc
526       //if Array
527       if(TYPE(header) > NUMCLASSES) {
528         int elementsize = classsize[TYPE(header)];
529         struct ArrayObject *ao = (struct ArrayObject *) (((char *)header) + sizeof(objheader_t));
530         int length = ao->___length___;
531         //check is stride is +ve or -ve
532         int sign;
533         if(GET_STRIDEINC(*(offsetarray+ (*depth) + 1))) {
534           sign = -1;
535         } else {
536           sign = 1;
537         }
538         int startelement = *(offsetarray + (*depth));
539         if(startelement < 0 || startelement >=length) {
540           printf("%s() Error: Offset out of range at %d\n", __func__, __LINE__);
541           odep->oid = 0;
542           odep->depth = 0;
543           return 0;
544         }
545         int index = *(dfsList+(*top)+1);
546         odep->oid = *((unsigned int *)(((char *)ao) + sizeof(struct ArrayObject) \
547                                        + (elementsize * (startelement + (sign*stride*index)))));
548         odep->depth = *(depth);
549       } else { //linked list
550         int dep;
551         int startelement;
552         if(range > 0) { //go to the next offset
553           startelement = *((int *)(offsetarray + (*depth) + 2));
554           *depth = *depth + 2;
555         } else if(range == 0) {
556           startelement = *((int *)(offsetarray + (*depth)));
557         } else { //range < 0
558           odep->oid = 0;
559           odep->depth = 0;
560           return 0;
561         }
562         odep->oid = *((unsigned int *)(((char *)header) + sizeof(objheader_t) + startelement));
563         odep->depth = *depth;
564       }
565     }
566   }
567   return 0;
568 }
569
570 unsigned int getNextArrayOid(short *offsetarray, unsigned int *dfsList, int *top, int* depth) {
571   int prev = (*top) - 2;
572   unsigned int oid = *(dfsList + prev);
573   if(oid == 0) { //null oid
574     return oid;
575   }
576   objheader_t *header = searchObj(oid);
577   if(header == NULL) {
578     printf("%s() Error: Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
579     return 0;
580   } else {
581     short stride = GET_STRIDE(*(offsetarray+(*depth) + 1));
582     stride++; //Note bit pattern 000 => stride = 1 etc
583     //check is stride is +ve or -ve
584     int sign;
585     if(GET_STRIDEINC(*(offsetarray+ (*depth) + 1))) {
586       sign = -1;
587     } else {
588       sign = 1;
589     }
590     int elementsize = classsize[TYPE(header)];
591     struct ArrayObject *ao = (struct ArrayObject *) (((char *)header) + sizeof(objheader_t));
592     int length = ao->___length___;
593     int startelement = *(offsetarray + (*depth));
594     if(startelement < 0 || startelement >=length) {
595       printf("%s() Error: Offset out of range at %d\n", __func__, __LINE__);
596       return 0;
597     }
598     int index = *(dfsList + *top + 1);
599     oid = *((unsigned int *)(((char *)ao) + sizeof(struct ArrayObject) \
600                              + (elementsize * (startelement + (sign*stride*index)))));
601   }
602   return oid;
603 }
604
605 unsigned int getNextPointerOid(short *offsetarray, unsigned int *dfsList, int *top, int* depth) {
606   int prev;
607   if(*(dfsList + *top + 1) > 1) { //tells which offset to calculate the oid from
608                                   //(if range > 1 then use available oid to compute next oid else go to previous oid)
609     prev = *top;
610   } else {
611     prev = *top - 2;
612   }
613   unsigned int oid = *(dfsList + prev);
614   if(oid == 0) { //null oid
615     return oid;
616   }
617   objheader_t *header = searchObj(oid);
618   if(header == NULL) {
619     printf("%s() Error: Object not found at %s , %d\n", __func__, __FILE__, __LINE__);
620     return 0;
621   } else {
622     int startelement = *(offsetarray + *depth);
623     oid = *((unsigned int *)(((char *)header) + sizeof(objheader_t) + startelement));
624     //TODO add optimization for checking if this oid has already not been found
625   }
626   return oid;
627 }
628
629 int sendOidFound(unsigned int oid, int sd) {
630   objheader_t *header;
631   if((header = (objheader_t *) mhashSearch(oid)) != NULL) {
632     ;
633   } else if((header = (objheader_t *) prehashSearch(oid))!=NULL) {
634     ;
635   } else {
636     printf("%s() Error: THIS SHOULD NOT HAPPEN at line %d in %s()\n", __func__, __LINE__, __FILE__);
637     return -1;
638   }
639
640   int incr = 0;
641   int objsize;
642   GETSIZE(objsize, header);
643   int size  = sizeof(int) + sizeof(char) + sizeof(unsigned int) + sizeof(objheader_t) + objsize;
644   char sendbuffer[size];
645   *((int *)(sendbuffer + incr)) = size;
646   incr += sizeof(int);
647   *((char *)(sendbuffer + incr)) = OBJECT_FOUND;
648   incr += sizeof(char);
649   *((unsigned int *)(sendbuffer + incr)) = oid;
650   incr += sizeof(unsigned int);
651   memcpy(sendbuffer + incr, header, objsize + sizeof(objheader_t));
652
653   char control = TRANS_PREFETCH_RESPONSE;
654   sendPrefetchResponse(sd, &control, sendbuffer, &size);
655   return 0;
656 }
657
658 int sendOidNotFound(unsigned int oid, int sd) {
659   int size  = sizeof(int) + sizeof(char) + sizeof(unsigned int);
660   char sendbuffer[size];
661   *((int *)sendbuffer) = size;
662   *((char *)(sendbuffer + sizeof(int))) = OBJECT_NOT_FOUND;
663   *((unsigned int *)(sendbuffer + sizeof(int) + sizeof(unsigned int))) = oid;
664   char control = TRANS_PREFETCH_RESPONSE;
665   sendPrefetchResponse(sd, &control, sendbuffer, &size);
666   return 0;
667 }