summaryrefslogtreecommitdiffstats
path: root/common/collection/collection.c
diff options
context:
space:
mode:
authorDmitri Pal <dpal@redhat.com>2009-07-09 13:02:45 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-07-15 11:19:45 -0400
commit1a91062d7d82407a6e376b62b29dca709170a66b (patch)
treef2ead880fe67a3991bdf2f998bfc70baf571ffeb /common/collection/collection.c
parentdf8b16d7d55d97001ed71f629fc21511ec9f8d3b (diff)
downloadsssd-1a91062d7d82407a6e376b62b29dca709170a66b.tar.gz
sssd-1a91062d7d82407a6e376b62b29dca709170a66b.tar.xz
sssd-1a91062d7d82407a6e376b62b29dca709170a66b.zip
COLLECTION Adding flat traversal & copy
The collection is hearachical. The flattening of the collection was not implemented before both for traversal and copying. This patch introduces functionality to traverse or iterate through collection as flat set and also copy collection into another flattening it and automatically resolving conflicts. Also imptoved tracability and fixed memory leak in unbind iterator code.
Diffstat (limited to 'common/collection/collection.c')
-rw-r--r--common/collection/collection.c278
1 files changed, 237 insertions, 41 deletions
diff --git a/common/collection/collection.c b/common/collection/collection.c
index 298ddf4d8..b4a2c8d5a 100644
--- a/common/collection/collection.c
+++ b/common/collection/collection.c
@@ -112,7 +112,8 @@ static int col_walk_items(struct collection_item *ci,
internal_item_fn traverse_handler,
void *traverse_data,
col_item_fn user_item_handler,
- void *custom_data);
+ void *custom_data,
+ unsigned *depth);
/* Function to get sub collection */
static int col_get_subcollection(const char *property,
@@ -283,6 +284,7 @@ static int col_find_property(struct collection_item *collection,
{
struct property_search ps;
int i = 0;
+ unsigned depth = 0;
TRACE_FLOW_STRING("col_find_property", "Entry.");
@@ -307,7 +309,8 @@ static int col_find_property(struct collection_item *collection,
/* We do not care about error here */
(void)col_walk_items(collection, COL_TRAVERSE_ONELEVEL,
col_parent_traverse_handler,
- (void *)parent, NULL, (void *)&ps);
+ (void *)parent, NULL, (void *)&ps,
+ &depth);
if (*parent) {
/* Item is found in the collection */
@@ -1221,13 +1224,14 @@ static void col_delete_path_data(struct path_data *path)
/* For each item walked it will call traverse handler.
Traverse handler accepts: current item,
user provided item handler and user provided custom data. */
-/* See below defferent traverse handlers for different cases */
+/* See below different traverse handlers for different cases */
static int col_walk_items(struct collection_item *ci,
int mode_flags,
internal_item_fn traverse_handler,
void *traverse_data,
col_item_fn user_item_handler,
- void *custom_data)
+ void *custom_data,
+ unsigned *depth)
{
struct collection_item *current;
struct collection_item *parent = NULL;
@@ -1238,6 +1242,9 @@ static int col_walk_items(struct collection_item *ci,
TRACE_FLOW_STRING("col_walk_items", "Entry.");
TRACE_INFO_NUMBER("Mode flags:", mode_flags);
+ /* Increase depth */
+ (*depth)++;
+
current = ci;
while (current) {
@@ -1252,22 +1259,34 @@ static int col_walk_items(struct collection_item *ci,
if ((mode_flags & COL_TRAVERSE_IGNORE) == 0) {
TRACE_INFO_STRING("Subcollection is not ignored.", "");
-
/* We are not ignoring sub collections */
- error = traverse_handler(ci, parent, current, traverse_data,
- user_item_handler, custom_data, &stop);
- if (stop != 0) {
- TRACE_INFO_STRING("Traverse handler returned STOP.", "");
- error = EINTR_INTERNAL;
- }
- /* Check what error we got */
- if (error == EINTR_INTERNAL) {
- TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error);
- return error;
- }
- else if (error) {
- TRACE_ERROR_NUMBER("Traverse handler returned error.", error);
- return error;
+
+ if ((mode_flags & COL_TRAVERSE_FLAT) == 0) {
+
+ TRACE_INFO_STRING("Subcollection is not flattened.", "");
+ /* We are not flattening sub collections.
+ * The flattening means that we are not going
+ * to return reference and headers for sub collections.
+ * We will also not do special end collection
+ * invocation for sub collections.
+ */
+ error = traverse_handler(ci, parent, current, traverse_data,
+ user_item_handler, custom_data, &stop);
+ if (stop != 0) {
+ TRACE_INFO_STRING("Traverse handler returned STOP.", "");
+ error = EINTR_INTERNAL;
+ }
+ /* Check what error we got */
+ if (error == EINTR_INTERNAL) {
+ TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error);
+ (*depth)--;
+ return error;
+ }
+ else if (error) {
+ TRACE_ERROR_NUMBER("Traverse handler returned error.", error);
+ (*depth)--;
+ return error;
+ }
}
if ((mode_flags & COL_TRAVERSE_ONELEVEL) == 0) {
@@ -1278,7 +1297,8 @@ static int col_walk_items(struct collection_item *ci,
/* We need to go into sub collections */
error = col_walk_items(sub, mode_flags,
traverse_handler, traverse_data,
- user_item_handler, custom_data);
+ user_item_handler, custom_data,
+ depth);
TRACE_INFO_STRING("Returned from sub collection processing", "");
TRACE_INFO_STRING("Done processing item:", current->property);
TRACE_INFO_NUMBER("Done processing item type:", current->type);
@@ -1286,12 +1306,29 @@ static int col_walk_items(struct collection_item *ci,
}
}
}
- else
- /* Call handler then move on */
- error = traverse_handler(ci, parent, current,
- traverse_data, user_item_handler,
- custom_data, &stop);
+ else {
+ /* Check if it is a header and we are not on the root level.
+ * If we are flattening collection we need to skip headers
+ * for sub collections.
+ */
+
+ /* Call handler if:
+ * a) It is not collection header
+ * OR
+ * b) It is header we are flattening but we are on top level
+ * OR
+ * c) It is header and we are not flattening.
+ */
+ if ((current->type != COL_TYPE_COLLECTION) ||
+ (((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) ||
+ ((mode_flags & COL_TRAVERSE_FLAT) == 0)) {
+ /* Call handler then move on */
+ error = traverse_handler(ci, parent, current,
+ traverse_data, user_item_handler,
+ custom_data, &stop);
+ }
+ }
/* If we are stopped - return EINTR_INTERNAL */
if (stop != 0) {
TRACE_INFO_STRING("Traverse handler returned STOP.", "");
@@ -1300,10 +1337,12 @@ static int col_walk_items(struct collection_item *ci,
/* Check what error we got */
if (error == EINTR_INTERNAL) {
TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error);
+ (*depth)--;
return error;
}
else if (error) {
TRACE_ERROR_NUMBER("Traverse handler returned error.", error);
+ (*depth)--;
return error;
}
@@ -1314,14 +1353,27 @@ static int col_walk_items(struct collection_item *ci,
TRACE_INFO_STRING("Out of loop", "");
+ /* Check if we need to have a special
+ * call at the end of the collection.
+ */
if ((mode_flags & COL_TRAVERSE_END) != 0) {
- TRACE_INFO_STRING("About to do the special end collection invocation of handler", "");
- error = traverse_handler(ci, parent, current,
- traverse_data, user_item_handler,
- custom_data, &stop);
+
+ /* Do this dummy invocation only:
+ * a) If we are flattening and on the root level
+ * b) We are not flattening
+ */
+ if ((((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) ||
+ ((mode_flags & COL_TRAVERSE_FLAT) == 0)) {
+
+ TRACE_INFO_STRING("About to do the special end collection invocation of handler", "");
+ error = traverse_handler(ci, parent, current,
+ traverse_data, user_item_handler,
+ custom_data, &stop);
+ }
}
TRACE_FLOW_NUMBER("col_walk_items. Returns: ", error);
+ (*depth)--;
return error;
}
@@ -1343,6 +1395,7 @@ static int col_find_item_and_do(struct collection_item *ci,
int error = EOK;
struct find_name *traverse_data = NULL;
+ unsigned depth = 0;
TRACE_FLOW_STRING("col_find_item_and_do", "Entry.");
@@ -1386,7 +1439,8 @@ static int col_find_item_and_do(struct collection_item *ci,
TRACE_INFO_NUMBER("Traverse flags", mode_flags);
error = col_walk_items(ci, mode_flags, col_act_traverse_handler,
- (void *)traverse_data, item_handler, custom_data);
+ (void *)traverse_data, item_handler, custom_data,
+ &depth);
if (traverse_data->current_path != NULL) {
TRACE_INFO_STRING("find_item_and_do",
@@ -1793,6 +1847,79 @@ static int col_copy_traverse_handler(struct collection_item *head,
return error;
}
+/* Function to copy collection as flat set */
+static int col_copy_collection_flat(struct collection_item *acceptor,
+ struct collection_item *donor)
+{
+ int error = EOK;
+ struct collection_iterator *iter = NULL;
+ struct collection_item *item = NULL;
+ struct collection_item *new_item = NULL;
+ struct collection_item *current = NULL;
+
+ TRACE_FLOW_STRING("col_copy_collection_flat", "Entry");
+
+ /* Bind iterator in flat mode */
+ error = col_bind_iterator(&iter, donor, COL_TRAVERSE_FLAT);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to bind iterator:", error);
+ return error;
+ }
+
+ /* Skip header */
+ error = col_iterate_collection(iter, &item);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to iterate on header:", error);
+ col_unbind_iterator(iter);
+ return error;
+ }
+
+ current = item->next;
+
+ while (current) {
+
+ /* Loop through a collection */
+ error = col_iterate_collection(iter, &item);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to iterate:", error);
+ col_unbind_iterator(iter);
+ return error;
+ }
+
+ /* Create new item */
+ error = col_allocate_item(&new_item,
+ item->property,
+ item->data,
+ item->length,
+ item->type);
+ if(error) {
+ TRACE_ERROR_NUMBER("Error allocating end item.", error);
+ col_unbind_iterator(iter);
+ return error;
+ }
+
+ /* Insert this item into collection */
+ error = col_insert_item(acceptor,
+ NULL,
+ new_item,
+ COL_DSP_END,
+ NULL,
+ 0,
+ COL_INSERT_DUPOVER);
+ if(error) {
+ TRACE_ERROR_NUMBER("Error allocating end item.", error);
+ col_unbind_iterator(iter);
+ col_delete_item(new_item);
+ return error;
+ }
+
+ current = item->next;
+ }
+
+ col_unbind_iterator(iter);
+ TRACE_FLOW_NUMBER("col_copy_collection_flat Exit returning", error);
+ return error;
+}
/********************* MAIN INTERFACE FUNCTIONS *****************************/
@@ -1889,6 +2016,7 @@ int col_copy_collection(struct collection_item **collection_copy,
struct collection_item *new_collection = NULL;
const char *name;
struct collection_header *header;
+ unsigned depth = 0;
TRACE_FLOW_STRING("col_copy_collection", "Entry.");
@@ -1909,7 +2037,7 @@ int col_copy_collection(struct collection_item **collection_copy,
error = col_walk_items(collection_to_copy, COL_TRAVERSE_ONELEVEL,
col_copy_traverse_handler, new_collection,
- NULL, NULL);
+ NULL, NULL, &depth);
if (!error) *collection_copy = new_collection;
else col_destroy_collection(new_collection);
@@ -2156,6 +2284,15 @@ int col_add_collection_to_collection(struct collection_item *ci,
TRACE_INFO_NUMBER("Adding property returned:", error);
break;
+ case COL_ADD_MODE_FLAT:
+ TRACE_INFO_STRING("We are flattening the collection.", "");
+
+ error = col_copy_collection_flat(acceptor, collection_to_add);
+
+ TRACE_INFO_NUMBER("Copy collection flat returned:", error);
+ break;
+
+
default:
error = EINVAL;
}
@@ -2175,10 +2312,12 @@ int col_traverse_collection(struct collection_item *ci,
{
int error = EOK;
+ unsigned depth = 0;
+
TRACE_FLOW_STRING("col_traverse_collection", "Entry.");
error = col_walk_items(ci, mode_flags, col_simple_traverse_handler,
- NULL, item_handler, custom_data);
+ NULL, item_handler, custom_data, &depth);
if ((error != 0) && (error != EINTR_INTERNAL)) {
TRACE_ERROR_NUMBER("Error walking tree", error);
@@ -2430,8 +2569,11 @@ int col_bind_iterator(struct collection_iterator **iterator,
iter->stack = NULL;
iter->stack_size = 0;
iter->stack_depth = 0;
+ iter->item_level = 0;
iter->flags = mode_flags;
+ TRACE_INFO_NUMBER("Iterator flags", iter->flags);
+
/* Allocate memory for stack */
error = col_grow_stack(iter, 1);
if(error) {
@@ -2491,13 +2633,31 @@ int col_get_iterator_depth(struct collection_iterator *iterator, int *depth)
return EINVAL;
}
- *depth = iterator->stack_depth -1;
+ *depth = iterator->stack_depth - 1;
TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth);
TRACE_FLOW_STRING("col_get_iterator_depth","Exit");
return EOK;
}
+/* What was the level of the last item we got? */
+int col_get_item_depth(struct collection_iterator *iterator, int *depth)
+{
+ TRACE_FLOW_STRING("col_get_item_depth", "Entry");
+
+ if ((iterator == NULL) || (depth == NULL)) {
+ TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
+ return EINVAL;
+ }
+
+ *depth = iterator->item_level;
+
+ TRACE_INFO_NUMBER("Item level at the end:", iterator->item_level);
+ TRACE_FLOW_STRING("col_get_item_depth","Exit");
+ return EOK;
+}
+
+
/* Unbind the iterator from the collection */
void col_unbind_iterator(struct collection_iterator *iterator)
@@ -2505,7 +2665,7 @@ void col_unbind_iterator(struct collection_iterator *iterator)
TRACE_FLOW_STRING("col_unbind_iterator", "Entry.");
if (iterator != NULL) {
col_destroy_collection(iterator->top);
- free(iterator->end_item);
+ col_delete_item(iterator->end_item);
free(iterator->stack);
free(iterator);
}
@@ -2541,6 +2701,7 @@ int col_iterate_collection(struct collection_iterator *iterator,
/* Is current item available */
current = iterator->stack[iterator->stack_depth - 1];
+ iterator->item_level = iterator->stack_depth - 1;
/* We are not done so check if we have an item */
if (current != NULL) {
@@ -2569,6 +2730,7 @@ int col_iterate_collection(struct collection_iterator *iterator,
TRACE_INFO_STRING("Instructed to show header not reference", "");
other = *((struct collection_item **)current->data);
iterator->stack[iterator->stack_depth] = other->next;
+ iterator->item_level = iterator->stack_depth;
*item = other;
}
/* Do we need to show both? */
@@ -2576,6 +2738,17 @@ int col_iterate_collection(struct collection_iterator *iterator,
TRACE_INFO_STRING("Instructed to show header and reference","");
iterator->stack[iterator->stack_depth] = *((struct collection_item **)(current->data));
*item = current;
+ /* Do not need to adjust level here */
+ }
+ /* Do not show either */
+ else if ((iterator->flags & COL_TRAVERSE_FLAT) != 0) {
+ TRACE_INFO_STRING("Instructed not to show header and reference","");
+ other = *((struct collection_item **)current->data);
+ iterator->stack[iterator->stack_depth] = other->next;
+ iterator->stack[iterator->stack_depth - 1] = current->next;
+ iterator->stack_depth++;
+ /* Do not need to adjust level here */
+ continue;
}
/* We need to show reference only */
else {
@@ -2589,6 +2762,8 @@ int col_iterate_collection(struct collection_iterator *iterator,
TRACE_INFO_NUMBER("Will show this item next time type:", other->next->type);
}
*item = current;
+ TRACE_INFO_NUMBER("Level of the reference:", iterator->item_level);
+ /* Do not need to adjust level here */
}
TRACE_INFO_STRING("We return item:", (*item)->property);
@@ -2616,9 +2791,18 @@ int col_iterate_collection(struct collection_iterator *iterator,
}
else {
/* Got a normal item - return it and move to the next one */
- TRACE_INFO_STRING("Simple item", "");
- *item = current;
- iterator->stack[iterator->stack_depth - 1] = current->next;
+ if ((current->type == COL_TYPE_COLLECTION) &&
+ ((iterator->flags & COL_TRAVERSE_FLAT) != 0) &&
+ (iterator->stack_depth > 1)) {
+ TRACE_INFO_STRING("Header of the sub collection in flat case ", "");
+ iterator->stack[iterator->stack_depth - 1] = current->next;
+ continue;
+ }
+ else {
+ TRACE_INFO_STRING("Simple item", "");
+ *item = current;
+ iterator->stack[iterator->stack_depth - 1] = current->next;
+ }
break;
}
}
@@ -2626,12 +2810,24 @@ int col_iterate_collection(struct collection_iterator *iterator,
/* Item is NULL */
TRACE_INFO_STRING("Finished level", "moving to upper level");
iterator->stack_depth--;
+ /* Remember that item_level is zero based while depth is size
+ * so we decrease and then assign. */
TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth);
if ((iterator->flags & COL_TRAVERSE_END) != 0) {
- /* Return dummy entry to indicate the end of the collection */
- TRACE_INFO_STRING("Finished level", "told to return END");
- *item = iterator->end_item;
- break;
+
+ /* Show end element
+ * a) If we are flattening but at the top
+ * b) We are not flattening
+ */
+ if ((((iterator->flags & COL_TRAVERSE_FLAT) != 0) &&
+ (iterator->stack_depth == 0)) ||
+ ((iterator->flags & COL_TRAVERSE_FLAT) == 0)) {
+
+ /* Return dummy entry to indicate the end of the collection */
+ TRACE_INFO_STRING("Finished level", "told to return END");
+ *item = iterator->end_item;
+ break;
+ }
}
else {
/* Move to next level */