/** * create a north load balancing object with AF_INET @param lbg_idx : reference of the load balancing group @param buf_p: pointer to the buffer to send @param rsp_size : expected response size in byte @param disk_time: estimated disk_time in us retval 0 : success retval -1 : error */ int north_lbg_send_with_shaping(int lbg_idx,void *buf_p,uint32_t rsp_size,uint32_t disk_time) { north_lbg_ctx_t *lbg_p; int ret = 0; lbg_p = north_lbg_getObjCtx_p(lbg_idx); if (lbg_p == NULL) { severe("north_lbg_send: no such instance %d ",lbg_idx); return -1; } if ((lbg_p->state == NORTH_LBG_SHUTTING_DOWN) || (lbg_p->free == TRUE)) { return -1; } /* ** we have the context, search for a valid entry */ if (lbg_p->state == NORTH_LBG_DOWN) { /* ** Insert the buffer in the global pending list of the load balancing froup */ ruc_objInsertTail((ruc_obj_desc_t*)&lbg_p->xmitList[0],(ruc_obj_desc_t*)buf_p); /* ** update statistics */ lbg_p->stats.xmitQueuelen++; return 0; } /* ** check if the main queue is empty if the queue is not empty just queue our message ** at the tail of the load balancer main queue */ if (!ruc_objIsEmptyList((ruc_obj_desc_t*)&lbg_p->xmitList[0])) { /* ** queue the message at the tail */ ruc_objInsertTail((ruc_obj_desc_t*)&lbg_p->xmitList[0],(ruc_obj_desc_t*)buf_p); /* ** update statistics */ lbg_p->stats.xmitQueuelen++; return 0; } /* ** call the traffic shaper */ ret = trshape_queue_buf(0,buf_p,rsp_size,disk_time,north_lbg_send_from_shaper,lbg_idx); return ret; }
/** * that callback is called upon the successful transmission of a buffer Depending on the inuse value of the buffer, the application can either release the message or queue it in its local xmit queue. The main purpose of queueing the message is to address the case of a disconnection of the remote end in order to re-balance the buffer on another equivalent destinatio @param userRef : pointer to a load balancer entry @param socket_context_ref: socket context reference @param bufRef : pointer to the packet buffer on which the error has been encountered @retval none */ void north_lbg_userXmiDoneCallBack(void *userRef,uint32_t socket_context_ref,void *bufRef) { int8_t inuse; north_lbg_entry_ctx_t *entry_p = (north_lbg_entry_ctx_t*)userRef; /* ** check the inuse value of the buffer, if inuse is 1, then release it */ inuse = ruc_buf_inuse_get(bufRef); if (inuse < 0) { //#warning inuse MUST never be negative so EXIT !!!!! fatal("fatal error on buffer management: inuse counter %d",inuse ); } if (inuse == 1) { ruc_buf_freeBuffer(bufRef); } else { /* ** queue it to the local xmit list of the entry */ ruc_objInsertTail((ruc_obj_desc_t*)&entry_p->xmitList,(ruc_obj_desc_t*)bufRef); } }
/*----------------------------------------------- ** north_lbg_alloc ** create a Transaction context ** That function tries to allocate a free PDP ** context. In case of success, it returns the ** index of the Transaction context. ** @param : recli index @param relayCref : RELAY-C ref of the context @retval : MS controller reference (if OK) @retval NULL if out of context. */ north_lbg_ctx_t *north_lbg_alloc() { north_lbg_ctx_t *p; /* ** Get the first free context */ if ((p = (north_lbg_ctx_t*) ruc_objGetFirst((ruc_obj_desc_t*) north_lbg_context_freeListHead)) == (north_lbg_ctx_t*) NULL) { /* ** out of Transaction context descriptor try to free some MS ** context that are out of date */ severe( "NOT ABLE TO GET an AF_UNIX CONTEXT" ); return NULL; } /* ** reinitilisation of the context */ north_lbg_ctxInit(p, FALSE); /* ** remove it for the linked list */ north_lbg_context_allocated++; p->free = FALSE; ruc_objRemove((ruc_obj_desc_t*) p); /* ** insert in the active list the new element created */ ruc_objInsertTail((ruc_obj_desc_t*) & north_lbg_context_activeListHead, (ruc_obj_desc_t*) p); return p; }
/*---------------------------------------------- ** Declare a server **---------------------------------------------- ** IN : ** . name : name of the server ** . nbEvent : number of events generated ** by the server ** ** OUT : Server reference or -1 **----------------------------------------------- */ uint32_t ruc_observer_declareServer(char * name, uint32_t nbEvent) { RUC_OBSERVER_SERVER_T * pSrv; uint32_t idx; if (ruc_observer_initDone == FALSE) { ERRFAT "OBSERVER not initialised" ENDERRFAT; return -1; } /* ** get the first element from the free list */ pSrv = (RUC_OBSERVER_SERVER_T*)ruc_objGetFirst((ruc_obj_desc_t*) ruc_observer_server_freeListHead); if (pSrv == (RUC_OBSERVER_SERVER_T* )NULL) { ERRFAT "Out of server context" ENDERRFAT; return -1; } /* ** remove the context from the free list */ ruc_objRemove(&pSrv->link); /* ** store the callback pointer,the user Reference and priority */ strncpy(pSrv->name,name,RUC_OBSERVER_NAME_MAX); pSrv->name[RUC_OBSERVER_NAME_MAX-1] = 0; pSrv->nbEvent = nbEvent; /* ** Allocate an event table */ pSrv->pEventTbl = (RUC_OBSERVER_EVENT_T *)malloc(nbEvent*sizeof(RUC_OBSERVER_EVENT_T)); if (pSrv->pEventTbl == (RUC_OBSERVER_EVENT_T*)NULL) { /* ** out of memory */ ERRFAT "Out of memory" ENDERRFAT; return -1; } /* ** initialize each event */ for (idx=0; idx < nbEvent; idx++) { pSrv->pEventTbl[idx].event = idx; pSrv->pEventTbl[idx].pnextCur = NULL; ruc_listHdrInit(&pSrv->pEventTbl[idx].head); } /* ** insert in the server active list */ ruc_objInsertTail(&ruc_observer_server_activeList.link, &pSrv->link); return (pSrv->ref); }
/** delete a AF_UNIX context That function is intended to be called when a Transaction context is deleted. It returns the Transaction context to the free list. The delete procedure of the MS automaton and controller are called by that service. If the Transaction context is out of limit, and error is returned. @param : MS Index @retval : RUC_OK : context has been deleted @retval RUC_NOK : out of limit index. */ uint32_t af_unix_free_from_idx(uint32_t af_unix_ctx_id) { af_unix_ctx_generic_t *p; if (af_unix_ctx_id >= af_unix_context_count) { /* ** index is out of limits */ return RUC_NOK; } /* ** get the reference from idx */ p = af_unix_getObjCtx_p(af_unix_ctx_id); /* ** remove the xmit block */ // ruc_objRemove((ruc_obj_desc_t *)&p->xmitCtx); /* ** Take care of the current index of the show */ if (next_display_af_unix_ctx == (ruc_obj_desc_t*)p) { ruc_objGetNext(&af_unix_context_activeListHead.link, &next_display_af_unix_ctx); } /* ** remove it from the active list */ ruc_objRemove((ruc_obj_desc_t*) p); /* ** insert it in the free list */ af_unix_context_allocated--; p->free = TRUE; ruc_objInsertTail((ruc_obj_desc_t*) af_unix_context_freeListHead, (ruc_obj_desc_t*) p); return RUC_OK; }
/** delete a context That function is intended to be called when a Transaction context is deleted. It returns the Transaction context to the free list. The delete procedure of the MS automaton and controller are called by that service. If the Transaction context is out of limit, and error is returned. @param : index of the context @retval : RUC_OK : context has been deleted @retval RUC_NOK : out of limit index. */ uint32_t geo_proc_free_from_idx(uint32_t context_id) { geo_proc_ctx_t *p; if (context_id >= geo_proc_context_count) { /* ** index is out of limits */ return RUC_NOK; } /* ** get the reference from idx */ p = geo_proc_getObjCtx_p(context_id); /* ** stop the timer */ geo_proc_stop_timer(p); /* ** remove it from the active list */ ruc_objRemove((ruc_obj_desc_t*) p); /* ** clear the local reference and remote reference */ p->local_ref.u32 = 0; p->remote_ref = 0; if (p->record_buf_p != NULL) { free(p->record_buf_p); p->record_buf_p = NULL; } /* ** insert it in the free list */ geo_proc_context_allocated--; p->free = TRUE; ruc_objInsertTail((ruc_obj_desc_t*) geo_proc_context_freeListHead, (ruc_obj_desc_t*) p); return RUC_OK; }
/* **---------------------------------------------- ** geo_ctx_tmr_start **---------------------------------------------- ** ** charging timer service starting request ** ** IN : p_refTim : reference of the timer cell to use ** date_s : requested time out date, in seconds ** p_callBack : client call back to call at time out ** cBParam : client parameter to provide at time out ** ** OUT : OK/NOK ** **----------------------------------------------- */ uint32_t geo_ctx_tmr_start (uint8_t tmr_slot, geo_ctx_tmr_cell_t *p_refTim, uint32_t date_s, geo_ctx_tmr_callBack_t p_callBack, void *cBParam ) { uint32_t ret; if (tmr_slot >= GEO_CTX_TMR_SLOT_MAX) { severe( "geo_ctx_tmr_start : slot out of range : %d ",tmr_slot ); return RUC_NOK; } /* ** timer cell dequeing from its current queue ** This dequeing is always attempted, even if not queued ** As the list primitive is protected, no initial check ** need to be done */ ruc_objRemove((ruc_obj_desc_t *)p_refTim); /* ** initialize context */ p_refTim->date_s = date_s + geo_ctx_time(); p_refTim->date_s &= GEO_CTX_TIMER_MAX_DATE; p_refTim->delay = date_s; p_refTim->p_callBack = p_callBack; p_refTim->cBParam = cBParam; ret=ruc_objInsertTail(&geo_ctx_tmr.queue[tmr_slot],(ruc_obj_desc_t*)p_refTim); if(ret!=RUC_OK){ severe( "Pb while inserting cell in queue, ret=%u", ret ); return(RUC_NOK); } return(RUC_OK); }
/** * Search if there is already a pending lookup for the same object @param buffer: rozofs fuse context @param parent: inode parent @param name: name to look for @retval 1 : found @retval 0: not found */ int rozofs_lookup_insert_queue(void *buffer,fuse_ino_t parent, const char *name,fuse_req_t req,int trc_idx,int lookup_flags) { ruc_obj_desc_t * phead; ruc_obj_desc_t * elt; ruc_obj_desc_t * pnext; rozofs_fuse_save_ctx_t *fuse_save_ctx_p; uint32_t hash; /* ** scan the pending lookup request searching for the same request (ino+name) */ hash = dentry_hash(parent,(char*)name); phead = &rozofs_lookup_queue[hash%ROZOFS_MAX_LKUP_QUEUE]; pnext = (ruc_obj_desc_t*)NULL; while ((elt = ruc_objGetNext(phead, &pnext)) != NULL) { /* ** Check if the inode and the name are the same */ fuse_save_ctx_p = (rozofs_fuse_save_ctx_t*)ruc_buf_getPayload(elt); if (fuse_save_ctx_p->parent != parent) continue; if (strcmp(name,fuse_save_ctx_p->name) !=0) continue; /* ** it is the same request: so queue it on the current one if there is enough room */ if (fuse_save_ctx_p->lkup_cpt < ROZOFS_MAX_PENDING_LKUP) { fuse_save_ctx_p->lookup_tb[fuse_save_ctx_p->lkup_cpt].req = req; fuse_save_ctx_p->lookup_tb[fuse_save_ctx_p->lkup_cpt].trc_idx = trc_idx; fuse_save_ctx_p->lookup_tb[fuse_save_ctx_p->lkup_cpt].flags = lookup_flags; fuse_save_ctx_p->lkup_cpt++; return 1; } } /* ** this a new request: insert it in the global pending list */ ruc_objInsertTail(phead,(ruc_obj_desc_t*)buffer); return 0; }
/** delete a load balancer That function is intended to be called when a Transaction context is deleted. It returns the Transaction context to the free list. The delete procedure of the MS automaton and controller are called by that service. If the Transaction context is out of limit, and error is returned. @param : load balancer object index @retval : RUC_OK : context has been deleted @retval RUC_NOK : out of limit index. */ uint32_t north_lbg_free_from_idx(uint32_t north_lbg_ctx_id) { north_lbg_ctx_t *p; if (north_lbg_ctx_id >= north_lbg_context_count) { /* ** index is out of limits */ return RUC_NOK; } /* ** get the reference from idx */ p = north_lbg_getObjCtx_p(north_lbg_ctx_id); /* ** remove the xmit block */ // ruc_objRemove((ruc_obj_desc_t *)&p->xmitCtx); /* ** remove it from the active list */ ruc_objRemove((ruc_obj_desc_t*) p); p->state = NORTH_LBG_DEPENDENCY; /* ** insert it in the free list */ north_lbg_context_allocated--; p->free = TRUE; ruc_objInsertTail((ruc_obj_desc_t*) north_lbg_context_freeListHead, (ruc_obj_desc_t*) p); return RUC_OK; }
/** * create a north load balancing object with AF_INET @param lbg_idx : reference of the load balancing group @param buf_p: pointer to the buffer to send retval 0 : success retval -1 : error */ int north_lbg_send(int lbg_idx,void *buf_p) { north_lbg_ctx_t *lbg_p; int entry_idx; int ret = 0; /* ** remove the buffer from any pending list */ ruc_objRemove((ruc_obj_desc_t*)buf_p); lbg_p = north_lbg_getObjCtx_p(lbg_idx); if (lbg_p == NULL) { severe("north_lbg_send: no such instance %d ",lbg_idx); return -1; } if ((lbg_p->state == NORTH_LBG_SHUTTING_DOWN) || (lbg_p->free == TRUE)) { return -1; } reloop: /* ** we have the context, search for a valid entry */ if (lbg_p->state == NORTH_LBG_DOWN) { /* ** Insert the buffer in the global pending list of the load balancing froup */ ruc_objInsertTail((ruc_obj_desc_t*)&lbg_p->xmitList[0],(ruc_obj_desc_t*)buf_p); /* ** update statistics */ lbg_p->stats.xmitQueuelen++; return 0; } /* ** check if the main queue is empty if the queue is not empty just queue our message ** at the tail of the load balancer main queue */ if (!ruc_objIsEmptyList((ruc_obj_desc_t*)&lbg_p->xmitList[0])) { /* ** queue the message at the tail */ ruc_objInsertTail((ruc_obj_desc_t*)&lbg_p->xmitList[0],(ruc_obj_desc_t*)buf_p); /* ** update statistics */ lbg_p->stats.xmitQueuelen++; return 0; } /* ** Check whether this LBG is in active/standby mode ** in this case send the message on the active connection */ if (lbg_p->active_standby_mode == 1) { /* ** No actibve entry elected. The LBG should nbe down !!! */ if (lbg_p->active_lbg_entry < 0) { /* ** queue the message at the tail */ ruc_objInsertTail((ruc_obj_desc_t*)&lbg_p->xmitList[0],(ruc_obj_desc_t*)buf_p); /* ** update statistics */ lbg_p->stats.xmitQueuelen++; return 0; } /* ** Get the active socket to send on */ entry_idx = lbg_p->active_lbg_entry; } else { /* ** OK there is at least one entry that is free, so get the next valid entry */ entry_idx = north_lbg_get_next_valid_entry(lbg_p); if (entry_idx < 0) { /* ** that situation must not occur since there is at leat one entry that is UP!!!! */ // RUC_WARNING(-1); return -1; } } /* ** That's fine, get the pointer to the entry in order to get its socket context reference */ north_lbg_entry_ctx_t *entry_p = &lbg_p->entry_tb[entry_idx]; NORTH_LBG_START_PROF((&entry_p->stats)); ret = af_unix_generic_send_stream_with_idx(entry_p->sock_ctx_ref,buf_p); NORTH_LBG_STOP_PROF((&entry_p->stats)); if (ret == 0) { /* ** set the timer to supervise the connection (it only affects client connections) */ if (lbg_p->userPollingCallBack != NULL) { af_unix_ctx_generic_t *this = af_unix_getObjCtx_p(entry_p->sock_ctx_ref); af_inet_enable_cnx_supervision(this); af_inet_set_cnx_tmo(this,lbg_p->tmo_supervision_in_sec*10*5); } lbg_p->stats.totalXmit++; entry_p->stats.totalXmit++; return 0; } /* ** retry on a next entry ** we might need to update the retry counter of the buffer ?? */ lbg_p->stats.totalXmitError++; goto reloop; return 0; }
/** ruc_obj_desc_t *ruc_listCreate_shared(uint32_t nbElements,uint32 size) creation of a double linked list. The input arguments are the number of elements and the size of an element. it is mandatory that the element includes ruc_obj_desc_t at the beginning of its structure. @param nbElements : number of elements to create @param size : size of the structure of an element (including the size of ruc_obj_desc_t). @param key: key of the shared memory @retval <> NULL: pointer to the head of list @retval == NULL: out of memory note : the number of elements must not include the head of list. */ ruc_obj_desc_t *ruc_listCreate_shared(uint32_t nbElements,uint32_t size,key_t key) { ruc_obj_desc_t *p,*phead; uint32_t listId; uint8_t *pbyte; int i; int shmid; RUC_LIST_TRC("listCreate_in_shared",nbElements,size,-1,-1); /* ** reject the creation if the size is less than the ** ruc_obj_desc_t structure size */ if (size < sizeof(ruc_obj_desc_t)) { RUC_WARNING(-1); return (ruc_obj_desc_t*)NULL; } /* ** if the size is not long word aligned, adjust the size ** to do it. */ if ((size & 0x3) != 0) { size = ((size & (~0x3)) + 4 ); } /* ** test that the size does not exceed 32 bits */ { uint32_t nbElementOrig; uint32_t memRequested; nbElementOrig = nbElements+1; if (nbElementOrig == 0) { RUC_WARNING(-1); return (ruc_obj_desc_t*)NULL; } memRequested = size*(nbElementOrig); nbElementOrig = memRequested/size; if (nbElementOrig != (nbElements+1)) { /* ** overlap */ RUC_LIST_TRC("listCreate_err",nbElementOrig,nbElements,-1,-1); RUC_WARNING(-1); return (ruc_obj_desc_t*)NULL; } } /* ** create the shared memory */ if ((shmid = shmget(key, size*(nbElements+1), IPC_CREAT | 0666)) < 0) { perror("shmget"); RUC_WARNING(errno); return (ruc_obj_desc_t*)NULL; } /* * Now we attach the segment to our data space. */ if ((p =(ruc_obj_desc_t *) shmat(shmid, NULL, 0)) == (ruc_obj_desc_t *) -1) { perror("shmat"); RUC_WARNING(errno); return (ruc_obj_desc_t*)NULL; } /* ** get the list Id for the new list */ listId = ruc_getListId(); /* ** store the reference of the shared memory */ ruc_list_shmid_table[listId] = shmid; /* ** head of list initialization */ phead = p; phead->ps = phead; phead->pp = phead; phead->sysRef = p; phead->type = RUC_LIST_HEAD; phead->countOrObjId = nbElements ; phead->eltSize = size; phead->usrEvtCode = 0; phead->listId = listId; pbyte = (uint8_t*)p; for (i = 0; i < nbElements; i++) { pbyte +=size; p = (ruc_obj_desc_t*)pbyte; /* ** initialize the element header */ ruc_listEltInit(p); p->sysRef = phead; p->type = RUC_LIST_ELEM; p->listId = phead->listId; /* ** insert in the list */ ruc_objInsertTail(phead,p); } RUC_LIST_TRC("listCreate_out",nbElements,size,phead,phead->listId); return phead; }