Beispiel #1
0
/**
 * \brief This function destroys layer stored at verse server
 */
void vs_layer_destroy(struct VSNode *node, struct VSLayer *layer)
{
	struct VSLayer *child_layer;
	struct VSLayerValue *item;
	struct VBucket *vbucket;

	/* Free values in all items */
	vbucket = (struct VBucket*)layer->values.lb.first;
	while(vbucket != NULL) {
		item = (struct VSLayerValue*)vbucket->data;
		free(item->value);
		vbucket = vbucket->next;
	}

	/* Destroy hashed array with items */
	v_hash_array_destroy(&layer->values);

	/* Set references to parent layer in all child layers to NULL */
	child_layer = layer->child_layers.first;
	while(child_layer != NULL) {
		child_layer->parent = NULL;
		child_layer = child_layer->next;
	}
	layer->child_layers.first = NULL;
	layer->child_layers.last = NULL;

	/* If this layer has parent layer, then remove this layer from
	 * parent linked list of child layers */
	if(layer->parent != NULL) {
		v_list_rem_item(&layer->parent->child_layers, layer);
	}

	/* Free list of followers and subscribers */
	v_list_free(&layer->layer_folls);
	v_list_free(&layer->layer_subs);

	v_print_log(VRS_PRINT_DEBUG_MSG, "Layer: %d destroyed\n", layer->id);

	/* Destroy this layer itself */
	v_hash_array_remove_item(&node->layers, layer);
	free(layer);
}
Beispiel #2
0
/**
 * \brief This function handle changing link between nodes
 */
int vs_handle_link_change(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *node_link)
{
	struct VSUser			*user = (struct VSUser*)vsession->user;
	struct VSNode			*old_parent_node, *parent_node, *child_node;
	struct VSLink			*link;
	struct VSNodeSubscriber	*node_subscriber;
	struct VSEntityFollower *node_follower;
	uint32					parent_node_id = UINT32(node_link->data[0]);
	uint32					child_node_id = UINT32(node_link->data[UINT32_SIZE]);
	int						i;

	/* Try to find child node */
	if((child_node = vs_node_find(vs_ctx, child_node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n",
				__FUNCTION__, __LINE__, child_node_id);
		return 0;
	}

	/* Child node has to be created */
	if(! (child_node->state == ENTITY_CREATED || child_node->state == ENTITY_CREATING)) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d node id: %d is not in NODE_CREATED state: %d\n",
				__FUNCTION__, __LINE__, child_node->id, child_node->state);
		return 0;
	}

	/* Is user owner of child node or can user write to child node? */
	if(vs_node_can_write(vsession, child_node) != 1) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d user: %s can't write to child node: %d (owner: %s)\n",
				__FUNCTION__, __LINE__, user->username, child_node->id,
				child_node->owner->username);
		return 0;
	}

	/* Old link */
	link = child_node->parent_link;

	/* Old parent node */
	old_parent_node = link->parent;

	/* Is user owner of old parent node or can user write to old parent node? */
	if(vs_node_can_write(vsession, old_parent_node) != 1) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d user: %s can't write to old parent node: %d (owner: %s)\n",
				__FUNCTION__, __LINE__, user->username, old_parent_node->id,
				old_parent_node->owner->username);
		return 0;
	}

	/* Try to find new parent node */
	if((parent_node = vs_node_find(vs_ctx, parent_node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n",
				__FUNCTION__, __LINE__, parent_node_id);
		return 0;
	}

	/* Parent node has to be created */
	if(! (parent_node->state == ENTITY_CREATED || parent_node->state == ENTITY_CREATING)) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d node (id: %d) is not in NODE_CREATED state: %d\n",
				__FUNCTION__, __LINE__, parent_node->id, parent_node->state);
		return 0;
	}

	/* Test if client doesn't want to recreate existing link */
	if( parent_node == old_parent_node) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d link between nodes (parent_id: %d) (child_id: %d) already exists\n",
				__FUNCTION__, __LINE__, parent_node->id, child_node->id);
		return 0;
	}

	/* Is user owner of parent node or can user write to parent node? */
	if(vs_node_can_write(vsession, parent_node) != 1) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d user: %s can't write to parent node: %d (owner: %s)\n",
				__FUNCTION__, __LINE__, user->username, parent_node->id,
				parent_node->owner->username);
		return 0;
	}

	/* Test, if new link could be created */
	if(vs_link_test_nodes(parent_node, child_node) != 1) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s():%d node: %d can't be child of node: %d\n",
				__FUNCTION__, __LINE__, child_node->id, parent_node->id);
		return 0;
	}

	/* Remove link from old parent node */
	v_list_rem_item(&old_parent_node->children_links, link);

	/* Add link to new parent node */
	v_list_add_tail(&parent_node->children_links, link);
	link->parent = parent_node;

	/* Update child node internal properties according new parent node */
	vs_link_update_child(parent_node, child_node);

	/* Update version in child node, parent node and old parent node */
	vs_node_inc_version(parent_node);
	vs_node_inc_version(child_node);
	vs_node_inc_version(old_parent_node);

	/* Subscribers of old and new parent node will receive information about
	 * changing link between nodes. Prevent double sending command Node_Link,
	 * when clients are subscribed to both nodes. */

	/* Set temporary value in all sessions */
	for(i=0; i<vs_ctx->max_sessions; i++) {
		vs_ctx->vsessions[i]->tmp = 0;
	}

	/* Send Node_Link command to subscribers of old parent node and set
	 * session temporary value */
	node_subscriber = old_parent_node->node_subs.first;
	while(node_subscriber != NULL) {
		if(vs_node_can_read(node_subscriber->session, old_parent_node) == 1) {
			node_subscriber->session->tmp = 1;
			vs_link_change_send(node_subscriber, link);
		}
		node_subscriber = node_subscriber->next;
	}

	/* When client is subscribed to the new parent node and aware of child
	 * node, then send to the client only node_link */
	node_follower = child_node->node_folls.first;
	while(node_follower != NULL) {
		if(node_follower->node_sub->session->tmp != 1) {
			vs_link_change_send(node_follower->node_sub, link);
			node_follower->node_sub->session->tmp = 1;
		}
		node_follower = node_follower->next;
	}

	/* Send Node_Create command to subscribers of new parent node, when
	 * subscribers were not subscribed to child node */
	node_subscriber = parent_node->node_subs.first;
	while(node_subscriber != NULL) {
		if(node_subscriber->session->tmp != 1) {
			if(vs_node_can_read(node_subscriber->session, parent_node) == 1) {
				vs_node_send_create(node_subscriber, child_node, NULL);
			}
		}
		node_subscriber = node_subscriber->next;
	}

	return 1;
}
Beispiel #3
0
/*
 * \brief This function pop command from queue with specific priority.
 *
 * Returned command is allocated on the heap and have to be free from calling
 * function. When *count is not NULL, then this function will write number of
 * commands with same ID that could be compressed on this address. When *len
 * is not NULL, then this function will write length of compressed commands
 * at this address. When *len value is not 0, then this value represents maximal
 * size of commands that could be removed from this priority queue.
 *
 * \param[in]	*out_queue	The pointer at list of priority queues
 * \param[in]	prio		The value of priority
 * \param[out]	*count		The pointer at count of commands with same id that
 * could be compressed.
 * \param[out]	*share		The size of address that could be shared
 * \param[out]	*len		The length of compressed commands.
 *
 * \return This function returns pointer at command. This command is allocated
 * at the heap.
 */
struct Generic_Cmd *v_out_queue_pop(struct VOutQueue *out_queue,
		uint8 prio,
		uint16 *count,
		int8 *share,
		uint16 *len)
{
	struct VPrioOutQueue *prio_queue = out_queue->queues[prio];
	struct VOutQueueCommand *queue_cmd;
	struct Generic_Cmd *cmd=NULL;
	int i, can_pop_cmd = 1;

	/* Lock mutex */
	pthread_mutex_lock(&out_queue->lock);

	/*printf("\tcount: %u, share: %u, len: %u\n", *count, *share, *len);*/

	queue_cmd = prio_queue->cmds.first;

	if(queue_cmd != NULL ) {
		cmd = (struct Generic_Cmd *)queue_cmd->vbucket->data;

		assert(cmd != NULL);

		/* Return value of count and length of compressed commands */
		if(queue_cmd->counter != NULL) {
			if(count != NULL) {
				*count = *queue_cmd->counter;
			}
			if(share != NULL) {
				*share = *queue_cmd->share;
			}
			if(len != NULL) {
				/* When *len value is not 0, then this value represents maximal
				 * size of buffer that could be filled with this priority queue. This
				 * function should return value, that is smaller or equal than this
				 * maximum. */
				if(*len != 0) {
					if(*len < *queue_cmd->len) {
						if (count != NULL) {
							*count = v_cmd_count(cmd, *len, *queue_cmd->share);
							/* FIXME: compute length and count correctly, when command is added to the queue */
							*count = ((*count) > (*queue_cmd->counter)) ? *queue_cmd->counter : *count;
							/* Is enough space in buffer to unpack this command? */
							if(*count == 0) {
								can_pop_cmd = 0;
							}
							*len = v_cmds_len(cmd, *count, *queue_cmd->share, 0);
						} else {
							can_pop_cmd = 0;
						}
					} else {
						*len = *queue_cmd->len;
					}
				} else {
					*len = *queue_cmd->len;
				}
			}
		} else {
			if(count != NULL) {
				*count = 0;
			}
			if(share != NULL) {
				*share = 0;
			}
			if(len != NULL) {
				if(v_cmd_size(cmd) > *len) {
					can_pop_cmd = 0;
				}
				*len = 0;
			}
		}

		/* Is it possible to pop command from the queue */
		if(can_pop_cmd == 1) {
			/* Remove command from hashed linked list */
			v_hash_array_remove_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd);

			/* Remove command from priority queue */
			v_list_rem_item(&prio_queue->cmds, queue_cmd);

			/* Update total count and size of commands */
			out_queue->count--;
			out_queue->size -= out_queue->cmds[cmd->id]->item_size;

			/* Update count and size of commands in subqueue with priority prio */
			out_queue->queues[prio]->count--;
			out_queue->queues[prio]->size -= out_queue->cmds[cmd->id]->item_size;

			/* If needed, then update counter of commands with the same id in the queue */
			if(queue_cmd->counter != NULL) {
				*queue_cmd->counter -= 1;
				/* Free values, when it's last command in the queue */
				if(*queue_cmd->counter == 0) {
					free(queue_cmd->counter);
					queue_cmd->counter = NULL;
					free(queue_cmd->share);
					queue_cmd->share = NULL;
					free(queue_cmd->len);
					queue_cmd->len = NULL;
				}
			}

			/* When this priority queue is empty now, then update summary of
			 * real priorities and it is possibly necessary to change maximal
			 * or minimal priority queue*/
			if(out_queue->queues[prio]->count == 0) {
				if(prio>=VRS_DEFAULT_PRIORITY) {
					out_queue->r_prio_sum_high -= out_queue->queues[prio]->r_prio;
				} else {
					out_queue->r_prio_sum_low -= out_queue->queues[prio]->r_prio;
				}

				if(out_queue->max_prio == prio && out_queue->min_prio != prio) {
					for(i=prio; i>=out_queue->min_prio; i--) {
						if(out_queue->queues[i]->count != 0) {
							out_queue->max_prio = i;
							break;
						}
					}
				} else if(out_queue->min_prio == prio && out_queue->max_prio != prio) {
					for(i=prio; i<=out_queue->max_prio; i++) {
						if(out_queue->queues[i]->count != 0) {
							out_queue->min_prio = i;
							break;
						}
					}
				} else if(out_queue->min_prio == prio && out_queue->max_prio == prio) {
					out_queue->min_prio = out_queue->max_prio = VRS_DEFAULT_PRIORITY;
				}
			}

			/* Free queue command */
			free(queue_cmd);
		} else {
			cmd = NULL;
		}
	}

	pthread_mutex_unlock(&out_queue->lock);

	return cmd;
}
Beispiel #4
0
/**
 * \brief This function adds command to the head or tail of the queue
 */
static int _v_out_queue_push(struct VOutQueue *out_queue,
		uint8 flag,
		uint8 prio,
		struct Generic_Cmd *cmd)
{
	struct VOutQueueCommand *queue_cmd;
	struct VBucket *vbucket;
	int ret = 1;

	assert(cmd!=NULL);

	/* Try to find command with the same address, when duplicities are not
	 * allowed in command queue */
	if(out_queue->cmds[cmd->id]->flag & REMOVE_HASH_DUPS) {
		vbucket = v_hash_array_find_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd);
		if(vbucket != NULL) {
			/* Bucket has to include not NULL pointer */
			assert(vbucket->ptr!=NULL);

			queue_cmd = (struct VOutQueueCommand*)vbucket->ptr;

			/* Remove old command from the queue if the priority is different
			 * and add command to the end of new priority queue */
			if(queue_cmd->prio != prio) {

				/* Remove old obsolete data */
				v_hash_array_remove_item(&out_queue->cmds[cmd->id]->cmds, vbucket->data);
				/* Remove old  command */
				v_list_rem_item(&out_queue->queues[queue_cmd->prio]->cmds, queue_cmd);

				/* Update size and count in old priority queue */
				out_queue->queues[queue_cmd->prio]->count--;
				out_queue->queues[queue_cmd->prio]->size -= out_queue->cmds[cmd->id]->item_size;

				/* If needed, then update counter of commands with the same id in the queue */
				if(queue_cmd->counter != NULL) {
					*queue_cmd->counter -= 1;
					if(*queue_cmd->counter == 0) {
						free(queue_cmd->counter);
						queue_cmd->counter = NULL;
						free(queue_cmd->share);
						queue_cmd->share = NULL;
						free(queue_cmd->len);
						queue_cmd->len = NULL;
					}
				}

				/* When this priority queue is empty now, then update summary of real priorities */
				if(out_queue->queues[queue_cmd->prio]->count == 0) {
					if(prio>=VRS_DEFAULT_PRIORITY)
						out_queue->r_prio_sum_high -= out_queue->queues[queue_cmd->prio]->r_prio;
					else
						out_queue->r_prio_sum_low -= out_queue->queues[queue_cmd->prio]->r_prio;
				}

				/* Update new priority command */
				queue_cmd->id = cmd->id;
				queue_cmd->prio = prio;

				if(out_queue->cmds[cmd->id]->flag & NOT_SHARE_ADDR) {
					_v_out_queue_command_add(out_queue->queues[prio], flag, 0, queue_cmd, cmd);
				} else {
					_v_out_queue_command_add(out_queue->queues[prio], flag, 1, queue_cmd, cmd);
				}

				/* Add data of the command to the hashed linked list */
				queue_cmd->vbucket = v_hash_array_add_item(&out_queue->cmds[cmd->id]->cmds, cmd, out_queue->cmds[cmd->id]->item_size);
				queue_cmd->vbucket->ptr = (void*)queue_cmd;

				assert(queue_cmd->vbucket->data != NULL);

				/* When this priority queue was empty, then update summary of real priorities */
				if(out_queue->queues[prio]->count == 0) {
					if(prio>=VRS_DEFAULT_PRIORITY)
						out_queue->r_prio_sum_high += out_queue->queues[prio]->r_prio;
					else
						out_queue->r_prio_sum_low += out_queue->queues[prio]->r_prio;
				}

				/* Update count and size in new priority queue */
				out_queue->queues[prio]->count++;
				out_queue->queues[prio]->size += out_queue->cmds[cmd->id]->item_size;

				/* If necessary update maximal or minimal priority */
				if(prio > out_queue->max_prio) {
					out_queue->max_prio = prio;
				} else if(prio < out_queue->min_prio) {
					out_queue->min_prio = prio;
				}

			} else {
				/* Debug print */
#if 0
				v_print_log(VRS_PRINT_DEBUG_MSG, "Replacing obsolete command with new\n");
				v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)vbucket->data);
				v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd);
#endif

				/* Destroy original command */
				v_cmd_destroy((struct Generic_Cmd**)&vbucket->data);

				/* Replace data of current queue command with new data */
				vbucket->data = (void*)cmd;
			}
		} else {
			/* Add new command in queue */
			queue_cmd = _v_out_queue_command_create(out_queue, flag, prio, cmd);

			if(queue_cmd == NULL) {
				ret = 0;
			}
		}
	} else {
		/* Add new command in queue */
		queue_cmd = _v_out_queue_command_create(out_queue, flag, prio, cmd);

		if(queue_cmd == NULL) {
			ret = 0;
		}
	}

	return ret;
}
Beispiel #5
0
/**
 * \brief This function removes packet with id from history of sent packets.
 * It removes all its commands from the command history too.
 *
 * \param[in]	*C		The verse context.
 * \param[in]	id		The ID of packet, the will be removed from the history.
 *
 * \return		This function returns 1, then packet with id was found in the history
 * and it returns 0 otherwise.
 */
int v_packet_history_rem_packet(struct vContext *C, uint32 id)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket_History *history = &dgram_conn->packet_history;
	struct VPacket *r_packet = CTX_r_packet(C);
	struct VSent_Packet *sent_packet;
	int ret = 0, is_fake_cmd_received = 0;

	sent_packet = v_packet_history_find_packet(history, id);

	if(sent_packet != NULL) {
		struct VSent_Command *sent_cmd;

		v_print_log(VRS_PRINT_DEBUG_MSG, "Removing packet: %d from history\n", sent_packet->id);

		/* Go through the whole list of sent commands and free them from the
		 * hashed linked list */
		sent_cmd = sent_packet->cmds.first;
		while(sent_cmd != NULL) {
			/* Remove own command from hashed linked list if it wasn't already
			 * removed, when command was obsoleted by some newer packet */
			if(sent_cmd->vbucket!=NULL) {
				struct Generic_Cmd *cmd = (struct Generic_Cmd*)sent_cmd->vbucket->data;

				/* Bucket has to include some data */
				assert(sent_cmd->vbucket->data!=NULL);

				/* Decrease total size of commands that were sent and wasn't acknowladged yet*/
				dgram_conn->sent_size -= v_cmd_size(cmd);

				/* Put fake command for create/destroy commands at verse server */
				if(vs_ctx != NULL) {
					struct VSession *vsession = CTX_current_session(C);
					struct Generic_Cmd *fake_cmd = NULL;

					switch(cmd->id) {
					case CMD_NODE_CREATE:
						fake_cmd = v_fake_node_create_ack_create(UINT32(cmd->data[UINT16_SIZE + UINT32_SIZE]));
						break;
					case CMD_NODE_DESTROY:
						fake_cmd = v_fake_node_destroy_ack_create(UINT32(cmd->data[0]));
						break;
					case CMD_TAGGROUP_CREATE:
						fake_cmd = v_fake_taggroup_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					case CMD_TAGGROUP_DESTROY:
						fake_cmd = v_fake_taggroup_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					case CMD_TAG_CREATE:
						fake_cmd = v_tag_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_TAG_DESTROY:
						fake_cmd = v_tag_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_LAYER_CREATE:
						fake_cmd = v_fake_layer_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_LAYER_DESTROY:
						fake_cmd = v_fake_layer_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					default:
						break;
					}

					if(fake_cmd != NULL) {
						is_fake_cmd_received = 1;
						/* Push command to the queue of incomming commands */
						v_in_queue_push(vsession->in_queue, fake_cmd);
						/* Print content of fake command */
						v_fake_cmd_print(VRS_PRINT_DEBUG_MSG, fake_cmd);
					}
				}

				/* Remove command from the history of sent commands */
				ret = v_hash_array_remove_item(&history->cmd_hist[sent_cmd->id]->cmds, sent_cmd->vbucket->data);

				if(ret == 1) {
					/* Destroy command */
					v_cmd_destroy(&cmd);
				} else {
					v_print_log(VRS_PRINT_ERROR, "Unable to remove command id: %d\n", sent_cmd->id);
					ret = 0;
				}
			}
			sent_cmd = sent_cmd->next;
		}

		/* Free linked list of sent commands */
		v_list_free(&sent_packet->cmds);

		/* Remove packet itself from the linked list of sent packet */
		v_list_rem_item(&history->packets, sent_packet);
		free(sent_packet);

		ret = 1;
	} else {
		/* When acknowledged payload packet is not found in history, then it
		 * is OK, because it is probably keep alive packet without any node
		 * commands */
		v_print_log(VRS_PRINT_DEBUG_MSG, "Packet with id: %d, not found in history\n", id);
	}

	/* When pure ack packet caused adding some fake commands to the queue, then
	 * poke server data thread */
	if( (vs_ctx != NULL) && (is_fake_cmd_received == 1) && (r_packet->data == NULL)) {
		sem_post(vs_ctx->data.sem);
	}

	return ret;
}