//-------------------------------------------------------------------------------------------------- ni_IteratorRef_t ni_CreateIterator ( le_msg_SessionRef_t sessionRef, ///< The user session this request occured on. tu_UserRef_t userRef, ///< Create the iterator for this user. tdb_TreeRef_t treeRef, ///< The tree to create the iterator with. ni_IteratorType_t type, ///< The type of iterator we are creating, read or write? const char* initialPathPtr ///< The node to move to in the specified tree. ) //-------------------------------------------------------------------------------------------------- { LE_ASSERT(sessionRef != NULL); LE_ASSERT(userRef != NULL); LE_ASSERT(treeRef != NULL); // Allocate the object and setup it's initial properties. ni_IteratorRef_t iteratorRef = le_mem_ForceAlloc(IteratorPoolRef); iteratorRef->sessionRef = sessionRef; iteratorRef->userRef = userRef; iteratorRef->treeRef = treeRef; iteratorRef->type = type; iteratorRef->reference = NULL; iteratorRef->isClosed = false; // If this is a write iterator, then shadow the tree instead of accessing it directly. if (iteratorRef->type == NI_WRITE) { iteratorRef->treeRef = tdb_ShadowTree(iteratorRef->treeRef); } // Get the root node of the requested tree, or if this is a write iterator... Get the shadowed // root node of the tree. iteratorRef->currentNodeRef = tdb_GetRootNode(iteratorRef->treeRef); iteratorRef->pathIterRef = le_pathIter_CreateForUnix("/"); LE_DEBUG("Created a new %s iterator object <%p> for user %u (%s) on tree %s.", TypeString(type), iteratorRef, tu_GetUserId(userRef), tu_GetUserName(userRef), tdb_GetTreeName(treeRef)); // If we were given an initial path, go to it now. Otherwise stay on the root node. if (initialPathPtr) { ni_GoToNode(iteratorRef, initialPathPtr); } // Update the tree so that it can keep track of this iterator. tdb_RegisterIterator(treeRef, iteratorRef); // All done. return iteratorRef; }
//-------------------------------------------------------------------------------------------------- le_result_t ni_GetNodeName ( ni_IteratorRef_t iteratorRef, ///< [IN] The iterator object to access. const char* pathPtr, ///< [IN] Optional path to another node in the tree. char* destBufferPtr, ///< [OUT] The buffer to copy string data into. size_t bufferMax ///< [IN] The maximum size of the string buffer. ) //-------------------------------------------------------------------------------------------------- { // Make sure we were given a buffer. if (bufferMax == 0) { return LE_OVERFLOW; } // If we have a current node, get it's name. Otherwise we'll have to get the name from the // path. tdb_NodeRef_t nodeRef = ni_GetNode(iteratorRef, pathPtr); // If the iterator was closed during the GetNode, then that means there was a fatal problem // encountered. if (iteratorRef->isTerminated) { // At this point we know the client has been disconnected. So just return fault so that the // calling code can know this. return LE_FAULT; } if (nodeRef != NULL) { return tdb_GetNodeName(nodeRef, destBufferPtr, bufferMax); } // Looks like a node wasn't found. So, try to get the name of the node from the sub-path. Or // if a sub-path was not specified, get the name from the iterator's base path. *destBufferPtr = '\0'; if (strcmp(pathPtr, "") != 0) { le_pathIter_Ref_t subPathIter = le_pathIter_CreateForUnix(pathPtr); le_result_t result = le_pathIter_GoToEnd(iteratorRef->pathIterRef); if (result == LE_OK) { result = le_pathIter_GetCurrentNode(subPathIter, destBufferPtr, bufferMax); } le_pathIter_Delete(subPathIter); return result; } LE_ASSERT(le_pathIter_GoToEnd(iteratorRef->pathIterRef) == LE_OK); return le_pathIter_GetCurrentNode(iteratorRef->pathIterRef, destBufferPtr, bufferMax); }
//-------------------------------------------------------------------------------------------------- tdb_NodeRef_t ni_GetNode ( ni_IteratorRef_t iteratorRef, ///< The iterator object to access. const char* subPathPtr ///< Optional, can be used to specify a node relative to the ///< current one. ) //-------------------------------------------------------------------------------------------------- { // Check to see if we have a current node. If we do, then attempt to traverse from our current // node, to the requested sub-node. If the new path is NULL or empty, then we'll just end up // getting our current node. if (iteratorRef->currentNodeRef != NULL) { le_pathIter_Ref_t newPathRef = le_pathIter_CreateForUnix(subPathPtr); tdb_NodeRef_t nodeRef = tdb_GetNode(iteratorRef->currentNodeRef, newPathRef); le_pathIter_Delete(newPathRef); return nodeRef; } // Ok, the iterator doesn't have a current node. So, copy iterator's existing path, and append // the new sub path to the existing path. Once that's done, attempt to find the requested node // in the tree. If the node still can not be found, return NULL. le_pathIter_Ref_t newPathRef = le_pathIter_Clone(iteratorRef->pathIterRef); tdb_NodeRef_t nodeRef = NULL; le_result_t result = LE_OK; if (subPathPtr != NULL) { result = le_pathIter_Append(newPathRef, subPathPtr); } // Make sure that the append was successful. If it is, get the node. if (result == LE_OVERFLOW) { tu_TerminateClient(iteratorRef->sessionRef, "Specified path too large."); } else if (result == LE_UNDERFLOW) { tu_TerminateClient(iteratorRef->sessionRef, "Specified path attempts to iterate below root."); } else { nodeRef = tdb_GetNode(tdb_GetRootNode(iteratorRef->treeRef), newPathRef); } le_pathIter_Delete(newPathRef); return nodeRef; }
static void TestUnixStyleAppends(void) { LE_INFO("======== Test Unix Style Appends."); { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/b/c/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/b/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../../x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../../../x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../../../../x/y/z") == LE_UNDERFLOW); LE_TEST(TestPath(iteratorRef, "/")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../../../x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "../../../../x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "../x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "/x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "/x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c"); LE_TEST(le_pathIter_Append(iteratorRef, "./x/y/z") == LE_OK); LE_TEST(TestPath(iteratorRef, "a/b/c/x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_Append(iteratorRef, "./x/y/./z") == LE_OK); LE_TEST(TestPath(iteratorRef, "./x/y/z")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_Append(iteratorRef, "/a//path/to/a///some/../place") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/to/a/place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_Create("", "::", "^^", "__"); LE_TEST(le_pathIter_Append(iteratorRef, "__::a::::path::to::__::a::some::^^::place") == LE_OK); LE_TEST(TestPath(iteratorRef, "__::a::path::to::a::place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_Create("::", "::", "^^", "__"); LE_TEST(le_pathIter_Append(iteratorRef, "__::a::::path::to::__::a::some::^^::place") == LE_OK); LE_TEST(TestPath(iteratorRef, "::a::path::to::a::place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_Create("", "/", NULL, NULL); LE_TEST(le_pathIter_Append(iteratorRef, "/a//path/./to/a///some/../place") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/./to/a/some/../place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_Append(iteratorRef, "../../../a//path/") == LE_OK); LE_TEST(TestPath(iteratorRef, "../../../a/path")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_Append(iteratorRef, "/a//path/to/a///some/../place") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/to/a/place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); LE_TEST(le_pathIter_GoToStart(iteratorRef) == LE_OK); LE_TEST(le_pathIter_GoToNext(iteratorRef) == LE_OK); LE_TEST(le_pathIter_GoToNext(iteratorRef) == LE_OK); LE_TEST(le_pathIter_GoToNext(iteratorRef) == LE_OK); le_pathIter_Truncate(iteratorRef); LE_TEST(le_pathIter_Append(iteratorRef, "nowhere") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/to/nowhere")); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_Append(iteratorRef, "/a//path/to/a///some/../place") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/to/a/place")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); LE_TEST(le_pathIter_Append(iteratorRef, "../../nowhere") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/path/to/nowhere")); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c"); LE_TEST(TestPath(iteratorRef, "/a/b/c")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/b")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/b/c/"); LE_TEST(TestPath(iteratorRef, "/a/b/c")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "/a/b")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c"); LE_TEST(TestPath(iteratorRef, "a/b/c")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "a/b")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/b/c/"); LE_TEST(TestPath(iteratorRef, "a/b/c")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "a/b")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a"); LE_TEST(TestPath(iteratorRef, "/a")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "/")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/a/"); LE_TEST(TestPath(iteratorRef, "/a")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "/")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == true); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a"); LE_TEST(TestPath(iteratorRef, "a")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } { le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("a/"); LE_TEST(TestPath(iteratorRef, "a")); LE_TEST(le_pathIter_Append(iteratorRef, "..") == LE_OK); LE_TEST(TestPath(iteratorRef, "")); LE_TEST(le_pathIter_IsAbsolute(iteratorRef) == false); le_pathIter_Delete(iteratorRef); } }
static void TestUnixStyleIterator(void) { LE_INFO("======== Test Unix Style Iterator."); static const char* nodes[] = { "a", "path", "to", "some", "end" }; static const char* nodes2[] = { "a", "b", "c", "d", "e" }; { static const char path[] = "/a/path/to/some/end"; le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(path); IteratePath(iteratorRef, path, nodes); le_pathIter_Delete(iteratorRef); } { static const char path[] = "::a::path::to::some::end"; le_pathIter_Ref_t iteratorRef = le_pathIter_Create(path, "::", "..", "."); IteratePath(iteratorRef, path, nodes); le_pathIter_Delete(iteratorRef); } { static const char path[] = "/a/b/c/d/e"; le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(path); IteratePath(iteratorRef, path, nodes2); le_pathIter_Delete(iteratorRef); } { static const char path[] = "::a::b::c::d::e"; le_pathIter_Ref_t iteratorRef = le_pathIter_Create(path, "::", "..", "."); IteratePath(iteratorRef, path, nodes2); le_pathIter_Delete(iteratorRef); } { char buffer[LARGE_BUFFER_SIZE] = { 0 }; le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix(""); LE_TEST(le_pathIter_GetCurrentNode(iteratorRef, buffer, LARGE_BUFFER_SIZE) == LE_NOT_FOUND); LE_TEST(strcmp(buffer, "") == 0); } { char buffer[LARGE_BUFFER_SIZE] = { 0 }; le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/"); le_pathIter_GoToStart(iteratorRef); LE_TEST(le_pathIter_GetCurrentNode(iteratorRef, buffer, LARGE_BUFFER_SIZE) == LE_NOT_FOUND); LE_TEST(strcmp(buffer, "") == 0); le_pathIter_GoToEnd(iteratorRef); LE_TEST(le_pathIter_GetCurrentNode(iteratorRef, buffer, LARGE_BUFFER_SIZE) == LE_NOT_FOUND); LE_TEST(strcmp(buffer, "") == 0); } { char buffer[LARGE_BUFFER_SIZE] = { 0 }; le_pathIter_Ref_t iteratorRef = le_pathIter_CreateForUnix("/some/path/somewhere"); le_pathIter_GoToStart(iteratorRef); LE_TEST(le_pathIter_GetCurrentNode(iteratorRef, buffer, LARGE_BUFFER_SIZE) == LE_OK); LE_TEST(strcmp(buffer, "some") == 0); le_pathIter_GoToEnd(iteratorRef); LE_TEST(le_pathIter_GetCurrentNode(iteratorRef, buffer, LARGE_BUFFER_SIZE) != LE_NOT_FOUND); LE_TEST(strcmp(buffer, "somewhere") == 0); } }
//-------------------------------------------------------------------------------------------------- ni_IteratorRef_t ni_CreateIterator ( le_msg_SessionRef_t sessionRef, ///< [IN] The user session this request occured on. tu_UserRef_t userRef, ///< [IN] Create the iterator for this user. tdb_TreeRef_t treeRef, ///< [IN] The tree to create the iterator with. ni_IteratorType_t type, ///< [IN] The type of iterator we are creating, read or write? const char* initialPathPtr ///< [IN] The node to move to in the specified tree. ) //-------------------------------------------------------------------------------------------------- { LE_ASSERT(treeRef != NULL); // Allocate the object and setup it's initial properties. ni_IteratorRef_t iteratorRef = le_mem_ForceAlloc(IteratorPoolRef); iteratorRef->creationTime = le_clk_GetRelativeTime(); iteratorRef->sessionRef = sessionRef; iteratorRef->userRef = userRef; iteratorRef->treeRef = treeRef; iteratorRef->type = type; iteratorRef->reference = NULL; iteratorRef->isClosed = false; iteratorRef->isTerminated = false; // Setup the timeout timer for this transaction, if it's been configured. time_t configTimeout = ic_GetTransactionTimeout(); if (configTimeout > 0) { le_clk_Time_t timeout = { configTimeout, 0 }; iteratorRef->timerRef = le_timer_Create("Transaction Timer"); LE_ASSERT(le_timer_SetInterval(iteratorRef->timerRef, timeout) == LE_OK); LE_ASSERT(le_timer_SetHandler(iteratorRef->timerRef, OnTransactionTimeout) == LE_OK); LE_ASSERT(le_timer_SetContextPtr(iteratorRef->timerRef, iteratorRef) == LE_OK); LE_ASSERT(le_timer_Start(iteratorRef->timerRef) == LE_OK); } else { iteratorRef->timerRef = NULL; } // If this is a write iterator, then shadow the tree instead of accessing it directly. if (iteratorRef->type == NI_WRITE) { iteratorRef->treeRef = tdb_ShadowTree(iteratorRef->treeRef); } // Get the root node of the requested tree, or if this is a write iterator... Get the shadowed // root node of the tree. iteratorRef->currentNodeRef = tdb_GetRootNode(iteratorRef->treeRef); iteratorRef->pathIterRef = le_pathIter_CreateForUnix("/"); LE_DEBUG("Created a new %s iterator object <%p> for user %u (%s) on tree %s.", TypeString(type), iteratorRef, tu_GetUserId(userRef), tu_GetUserName(userRef), tdb_GetTreeName(treeRef)); // If we were given an initial path, go to it now. Otherwise stay on the root node. if (initialPathPtr) { ni_GoToNode(iteratorRef, initialPathPtr); } // Update the tree so that it can keep track of this iterator. tdb_RegisterIterator(treeRef, iteratorRef); // All done. return iteratorRef; }