⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ctdb_call.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
	call.call_data.dsize = c->calldatalen;	/* determine if we are the dmaster for this key. This also	   fetches the record data (if any), thus avoiding a 2nd fetch of the data 	   if the call will be answered locally */	ret = ctdb_ltdb_lock_fetch_requeue(ctdb_db, call.key, &header, hdr, &data,					   ctdb_call_input_pkt, ctdb, False);	if (ret == -1) {		ctdb_send_error(ctdb, hdr, ret, "ltdb fetch failed in ctdb_request_call");		return;	}	if (ret == -2) {		DEBUG(2,(__location__ " deferred ctdb_request_call\n"));		return;	}	/* if we are not the dmaster, then send a redirect to the	   requesting node */	if (header.dmaster != ctdb->vnn) {		talloc_free(data.dptr);		ctdb_call_send_redirect(ctdb, call.key, c, &header);		ctdb_ltdb_unlock(ctdb_db, call.key);		return;	}	if (c->hopcount > ctdb->statistics.max_hop_count) {		ctdb->statistics.max_hop_count = c->hopcount;	}	/* if this nodes has done enough consecutive calls on the same record	   then give them the record	   or if the node requested an immediate migration	*/	if ( c->hdr.srcnode != ctdb->vnn &&	     ((header.laccessor == c->hdr.srcnode	       && header.lacount >= ctdb->tunable.max_lacount)	      || (c->flags & CTDB_IMMEDIATE_MIGRATION)) ) {		DEBUG(2,("vnn %u starting migration of %08x to %u\n", 			 ctdb->vnn, ctdb_hash(&call.key), c->hdr.srcnode));		ctdb_call_send_dmaster(ctdb_db, c, &header, &call.key, &data);		talloc_free(data.dptr);		ctdb_ltdb_unlock(ctdb_db, call.key);		return;	}	ctdb_call_local(ctdb_db, &call, &header, hdr, &data, c->hdr.srcnode);	ctdb_ltdb_unlock(ctdb_db, call.key);	len = offsetof(struct ctdb_reply_call, data) + call.reply_data.dsize;	r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CALL, len, 				    struct ctdb_reply_call);	CTDB_NO_MEMORY_FATAL(ctdb, r);	r->hdr.destnode  = hdr->srcnode;	r->hdr.reqid     = hdr->reqid;	r->status        = call.status;	r->datalen       = call.reply_data.dsize;	if (call.reply_data.dsize) {		memcpy(&r->data[0], call.reply_data.dptr, call.reply_data.dsize);	}	ctdb_queue_packet(ctdb, &r->hdr);	talloc_free(r);}/*  called when a CTDB_REPLY_CALL packet comes in  This packet comes in response to a CTDB_REQ_CALL request packet. It  contains any reply data from the call*/void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr){	struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;	struct ctdb_call_state *state;	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);	if (state == NULL) {		DEBUG(0, (__location__ " reqid %u not found\n", hdr->reqid));		return;	}	if (hdr->reqid != state->reqid) {		/* we found a record  but it was the wrong one */		DEBUG(0, ("Dropped orphaned call reply with reqid:%u\n",hdr->reqid));		return;	}	state->call.reply_data.dptr = c->data;	state->call.reply_data.dsize = c->datalen;	state->call.status = c->status;	talloc_steal(state, c);	state->state = CTDB_CALL_DONE;	if (state->async.fn) {		state->async.fn(state);	}}/*  called when a CTDB_REPLY_DMASTER packet comes in  This packet comes in from the lmaster response to a CTDB_REQ_CALL  request packet. It means that the current dmaster wants to give us  the dmaster role*/void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr){	struct ctdb_reply_dmaster *c = (struct ctdb_reply_dmaster *)hdr;	struct ctdb_db_context *ctdb_db;	TDB_DATA key, data;	int ret;	ctdb_db = find_ctdb_db(ctdb, c->db_id);	if (ctdb_db == NULL) {		DEBUG(0,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id));		return;	}		key.dptr = c->data;	key.dsize = c->keylen;	data.dptr = &c->data[key.dsize];	data.dsize = c->datalen;	ret = ctdb_ltdb_lock_requeue(ctdb_db, key, hdr,				     ctdb_call_input_pkt, ctdb, False);	if (ret == -2) {		return;	}	if (ret != 0) {		DEBUG(0,(__location__ " Failed to get lock in ctdb_reply_dmaster\n"));		return;	}	ctdb_become_dmaster(ctdb_db, hdr->reqid, key, data, c->rsn);}/*  called when a CTDB_REPLY_ERROR packet comes in*/void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr){	struct ctdb_reply_error *c = (struct ctdb_reply_error *)hdr;	struct ctdb_call_state *state;	state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state);	if (state == NULL) {		DEBUG(0,("vnn %u Invalid reqid %u in ctdb_reply_error\n",			 ctdb->vnn, hdr->reqid));		return;	}	if (hdr->reqid != state->reqid) {		/* we found a record  but it was the wrong one */		DEBUG(0, ("Dropped orphaned error reply with reqid:%u\n",hdr->reqid));		return;	}	talloc_steal(state, c);	state->state  = CTDB_CALL_ERROR;	state->errmsg = (char *)c->msg;	if (state->async.fn) {		state->async.fn(state);	}}/*  destroy a ctdb_call*/static int ctdb_call_destructor(struct ctdb_call_state *state){	DLIST_REMOVE(state->ctdb_db->ctdb->pending_calls, state);	ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);	return 0;}/*  called when a ctdb_call needs to be resent after a reconfigure event*/static void ctdb_call_resend(struct ctdb_call_state *state){	struct ctdb_context *ctdb = state->ctdb_db->ctdb;	state->generation = ctdb->vnn_map->generation;	/* use a new reqid, in case the old reply does eventually come in */	ctdb_reqid_remove(ctdb, state->reqid);	state->reqid = ctdb_reqid_new(ctdb, state);	state->c->hdr.reqid = state->reqid;	/* update the generation count for this request, so its valid with the new vnn_map */	state->c->hdr.generation = state->generation;	/* send the packet to ourselves, it will be redirected appropriately */	state->c->hdr.destnode = ctdb->vnn;	ctdb_queue_packet(ctdb, &state->c->hdr);	DEBUG(0,("resent ctdb_call\n"));}/*  resend all pending calls on recovery */void ctdb_call_resend_all(struct ctdb_context *ctdb){	struct ctdb_call_state *state, *next;	for (state=ctdb->pending_calls;state;state=next) {		next = state->next;		ctdb_call_resend(state);	}}/*  this allows the caller to setup a async.fn */static void call_local_trigger(struct event_context *ev, struct timed_event *te, 		       struct timeval t, void *private_data){	struct ctdb_call_state *state = talloc_get_type(private_data, struct ctdb_call_state);	if (state->async.fn) {		state->async.fn(state);	}}	/*  construct an event driven local ctdb_call  this is used so that locally processed ctdb_call requests are processed  in an event driven manner*/struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, 					     struct ctdb_call *call,					     struct ctdb_ltdb_header *header,					     TDB_DATA *data){	struct ctdb_call_state *state;	struct ctdb_context *ctdb = ctdb_db->ctdb;	int ret;	state = talloc_zero(ctdb_db, struct ctdb_call_state);	CTDB_NO_MEMORY_NULL(ctdb, state);	talloc_steal(state, data->dptr);	state->state = CTDB_CALL_DONE;	state->call = *call;	state->ctdb_db = ctdb_db;	ret = ctdb_call_local(ctdb_db, &state->call, header, state, data, ctdb->vnn);	event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);	return state;}/*  make a remote ctdb call - async send. Called in daemon context.  This constructs a ctdb_call request and queues it for processing.   This call never blocks.*/struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctdb_db, 						     struct ctdb_call *call, 						     struct ctdb_ltdb_header *header){	uint32_t len;	struct ctdb_call_state *state;	struct ctdb_context *ctdb = ctdb_db->ctdb;	state = talloc_zero(ctdb_db, struct ctdb_call_state);	CTDB_NO_MEMORY_NULL(ctdb, state);	state->reqid = ctdb_reqid_new(ctdb, state);	state->ctdb_db = ctdb_db;	talloc_set_destructor(state, ctdb_call_destructor);	len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;	state->c = ctdb_transport_allocate(ctdb, state, CTDB_REQ_CALL, len, 					   struct ctdb_req_call);	CTDB_NO_MEMORY_NULL(ctdb, state->c);	state->c->hdr.destnode  = header->dmaster;	/* this limits us to 16k outstanding messages - not unreasonable */	state->c->hdr.reqid     = state->reqid;	state->c->flags         = call->flags;	state->c->db_id         = ctdb_db->db_id;	state->c->callid        = call->call_id;	state->c->hopcount      = 0;	state->c->keylen        = call->key.dsize;	state->c->calldatalen   = call->call_data.dsize;	memcpy(&state->c->data[0], call->key.dptr, call->key.dsize);	memcpy(&state->c->data[call->key.dsize], 	       call->call_data.dptr, call->call_data.dsize);	state->call                = *call;	state->call.call_data.dptr = &state->c->data[call->key.dsize];	state->call.key.dptr       = &state->c->data[0];	state->state  = CTDB_CALL_WAIT;	state->generation = ctdb->vnn_map->generation;	DLIST_ADD(ctdb->pending_calls, state);	ctdb_queue_packet(ctdb, &state->c->hdr);	return state;}/*  make a remote ctdb call - async recv - called in daemon context  This is called when the program wants to wait for a ctdb_call to complete and get the   results. This call will block unless the call has already completed.*/int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call){	while (state->state < CTDB_CALL_DONE) {		event_loop_once(state->ctdb_db->ctdb->ev);	}	if (state->state != CTDB_CALL_DONE) {		ctdb_set_error(state->ctdb_db->ctdb, "%s", state->errmsg);		talloc_free(state);		return -1;	}	if (state->call.reply_data.dsize) {		call->reply_data.dptr = talloc_memdup(state->ctdb_db->ctdb,						      state->call.reply_data.dptr,						      state->call.reply_data.dsize);		call->reply_data.dsize = state->call.reply_data.dsize;	} else {		call->reply_data.dptr = NULL;		call->reply_data.dsize = 0;	}	call->status = state->call.status;	talloc_free(state);	return 0;}/*    send a keepalive packet to the other node*/void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode){	struct ctdb_req_keepalive *r;		r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_KEEPALIVE,				    sizeof(struct ctdb_req_keepalive), 				    struct ctdb_req_keepalive);	CTDB_NO_MEMORY_FATAL(ctdb, r);	r->hdr.destnode  = destnode;	r->hdr.reqid     = 0;		ctdb->statistics.keepalive_packets_sent++;	ctdb_queue_packet(ctdb, &r->hdr);	talloc_free(r);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -