Пример #1
0
//--------------------------------------------------------------------------------------------------
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;
}
Пример #2
0
//--------------------------------------------------------------------------------------------------
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);
}
Пример #3
0
//--------------------------------------------------------------------------------------------------
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;
}
Пример #4
0
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);
    }
}
Пример #5
0
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);
    }
}
Пример #6
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;
}