123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 |
- /**
- * @file IxEthDBDBPortUpdate.c
- *
- * @brief Implementation of dependency and port update handling
- *
- * @par
- * IXP400 SW Release version 2.0
- *
- * -- Copyright Notice --
- *
- * @par
- * Copyright 2001-2005, Intel Corporation.
- * All rights reserved.
- *
- * @par
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Intel Corporation nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * @par
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @par
- * -- End of Copyright Notice --
- */
- #include "IxEthDB_p.h"
- /* forward prototype declarations */
- IX_ETH_DB_PRIVATE MacTreeNode* ixEthDBTreeInsert(MacTreeNode *searchTree, MacDescriptor *descriptor);
- IX_ETH_DB_PRIVATE void ixEthDBCreateTrees(IxEthDBPortMap updatePorts);
- IX_ETH_DB_PRIVATE MacTreeNode* ixEthDBTreeRebalance(MacTreeNode *searchTree);
- IX_ETH_DB_PRIVATE void ixEthDBRebalanceTreeToVine(MacTreeNode *root, UINT32 *size);
- IX_ETH_DB_PRIVATE void ixEthDBRebalanceVineToTree(MacTreeNode *root, UINT32 size);
- IX_ETH_DB_PRIVATE void ixEthDBRebalanceCompression(MacTreeNode *root, UINT32 count);
- IX_ETH_DB_PRIVATE UINT32 ixEthDBRebalanceLog2Floor(UINT32 x);
- extern HashTable dbHashtable;
- /**
- * @brief register types requiring automatic updates
- *
- * @param typeArray array indexed on record types, each
- * element indicating whether the record type requires an
- * automatic update (TRUE) or not (FALSE)
- *
- * Automatic updates are done for registered record types
- * upon adding, updating (that is, updating the record portID)
- * and removing records. Whenever an automatic update is triggered
- * the appropriate ports will be provided with new database
- * information.
- *
- * It is assumed that the typeArray parameter is allocated large
- * enough to hold all the user defined types. Also, the type
- * array should be initialized to FALSE as this function only
- * caters for types which do require automatic updates.
- *
- * Note that this function should be called by the component
- * initialization function.
- *
- * @return number of record types registered for automatic
- * updates
- *
- * @internal
- */
- IX_ETH_DB_PUBLIC
- UINT32 ixEthDBUpdateTypeRegister(BOOL *typeArray)
- {
- typeArray[IX_ETH_DB_FILTERING_RECORD] = TRUE;
- typeArray[IX_ETH_DB_FILTERING_VLAN_RECORD] = TRUE;
- return 2;
- }
- /**
- * @brief computes dependencies and triggers port learning tree updates
- *
- * @param triggerPorts port map consisting in the ports which triggered the update
- *
- * This function browses through all the ports and determines how to waterfall the update
- * event from the trigger ports to all other ports depending on them.
- *
- * Once the list of ports to be updated is determined this function
- * calls @ref ixEthDBCreateTrees.
- *
- * @internal
- */
- IX_ETH_DB_PUBLIC
- void ixEthDBUpdatePortLearningTrees(IxEthDBPortMap triggerPorts)
- {
- IxEthDBPortMap updatePorts;
- UINT32 portIndex;
-
- ixEthDBUpdateLock();
-
- SET_EMPTY_DEPENDENCY_MAP(updatePorts);
-
- for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
- {
- PortInfo *port = &ixEthDBPortInfo[portIndex];
- BOOL mapsCollide;
-
- MAPS_COLLIDE(mapsCollide, triggerPorts, port->dependencyPortMap);
- if (mapsCollide /* do triggers influence this port? */
- && !IS_PORT_INCLUDED(portIndex, updatePorts) /* and it's not already in the update list */
- && port->updateMethod.updateEnabled) /* and we're allowed to update it */
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Adding port %d to update set\n", portIndex);
- JOIN_PORT_TO_MAP(updatePorts, portIndex);
- }
- else
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Didn't add port %d to update set, reasons follow:\n", portIndex);
- if (!mapsCollide)
- {
- IX_ETH_DB_UPDATE_TRACE("\tMaps don't collide on port %d\n", portIndex);
- }
- if (IS_PORT_INCLUDED(portIndex, updatePorts))
- {
- IX_ETH_DB_UPDATE_TRACE("\tPort %d is already in the update set\n", portIndex);
- }
- if (!port->updateMethod.updateEnabled)
- {
- IX_ETH_DB_UPDATE_TRACE("\tPort %d doesn't have updateEnabled set\n", portIndex);
- }
- }
- }
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Updating port set\n");
- ixEthDBCreateTrees(updatePorts);
-
- ixEthDBUpdateUnlock();
- }
- /**
- * @brief creates learning trees and calls the port update handlers
- *
- * @param updatePorts set of ports in need of learning trees
- *
- * This function determines the optimal method of creating learning
- * trees using a minimal number of database queries, keeping in mind
- * that different ports can either use the same learning trees or they
- * can partially share them. The actual tree building routine is
- * @ref ixEthDBQuery.
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- void ixEthDBCreateTrees(IxEthDBPortMap updatePorts)
- {
- UINT32 portIndex;
- BOOL result;
- BOOL portsLeft = TRUE;
- while (portsLeft)
- {
- /* get port with minimal dependency map and NULL search tree */
- UINT32 minPortIndex = MAX_PORT_SIZE;
- UINT32 minimalSize = MAX_PORT_SIZE;
- for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
- {
- UINT32 size;
- PortInfo *port = &ixEthDBPortInfo[portIndex];
- /* generate trees only for ports that need them */
- if (!port->updateMethod.searchTreePendingWrite && IS_PORT_INCLUDED(portIndex, updatePorts))
- {
- GET_MAP_SIZE(port->dependencyPortMap, size);
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Dependency map for port %d: size %d\n",
- portIndex, size);
- if (size < minimalSize)
- {
- minPortIndex = portIndex;
- minimalSize = size;
- }
- }
- else
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Skipped port %d from tree diff (%s)\n", portIndex,
- port->updateMethod.searchTreePendingWrite ? "pending write access" : "ignored by query");
- }
- }
- /* if a port was found than minimalSize is not MAX_PORT_SIZE */
- if (minimalSize != MAX_PORT_SIZE)
- {
- /* minPortIndex is the port we seek */
- PortInfo *port = &ixEthDBPortInfo[minPortIndex];
- IxEthDBPortMap query;
- MacTreeNode *baseTree;
- /* now try to find a port with minimal map difference */
- PortInfo *minimalDiffPort = NULL;
- UINT32 minimalDiff = MAX_PORT_SIZE;
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Minimal size port is %d\n", minPortIndex);
- for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
- {
- PortInfo *diffPort = &ixEthDBPortInfo[portIndex];
- BOOL mapIsSubset;
-
- IS_MAP_SUBSET(mapIsSubset, diffPort->dependencyPortMap, port->dependencyPortMap);
-
- if (portIndex != minPortIndex
- && diffPort->updateMethod.searchTree != NULL
- && mapIsSubset)
- {
- /* compute size and pick only minimal size difference */
- UINT32 diffPortSize;
- UINT32 sizeDifference;
- GET_MAP_SIZE(diffPort->dependencyPortMap, diffPortSize);
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Checking port %d for differences...\n", portIndex);
- sizeDifference = minimalSize - diffPortSize;
- if (sizeDifference < minimalDiff)
- {
- minimalDiffPort = diffPort;
- minimalDiff = sizeDifference;
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Minimal difference 0x%x was found on port %d\n",
- minimalDiff, portIndex);
- }
- }
- }
- /* check if filtering is enabled on this port */
- if ((port->featureStatus & IX_ETH_DB_FILTERING) != 0)
- {
- /* if minimalDiff is not MAX_PORT_SIZE minimalDiffPort points to the most similar port */
- if (minimalDiff != MAX_PORT_SIZE)
- {
- baseTree = ixEthDBCloneMacTreeNode(minimalDiffPort->updateMethod.searchTree);
- DIFF_MAPS(query, port->dependencyPortMap , minimalDiffPort->dependencyPortMap);
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Found minimal diff, extending tree %d on query\n",
- minimalDiffPort->portID);
- }
- else /* .. otherwise no similar port was found, build tree from scratch */
- {
- baseTree = NULL;
-
- COPY_DEPENDENCY_MAP(query, port->dependencyPortMap);
-
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) No similar diff, creating tree from query\n");
- }
- IS_EMPTY_DEPENDENCY_MAP(result, query);
-
- if (!result) /* otherwise we don't need anything more on top of the cloned tree */
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Adding query tree to port %d\n", minPortIndex);
-
- /* build learning tree */
- port->updateMethod.searchTree = ixEthDBQuery(baseTree, query, IX_ETH_DB_ALL_FILTERING_RECORDS, MAX_ELT_SIZE);
- }
- else
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) Query is empty, assuming identical nearest tree\n");
-
- port->updateMethod.searchTree = baseTree;
- }
- }
- else
- {
- /* filtering is not enabled, will download an empty tree */
- if (port->updateMethod.searchTree != NULL)
- {
- ixEthDBFreeMacTreeNode(port->updateMethod.searchTree);
- }
- port->updateMethod.searchTree = NULL;
- }
- /* mark tree as valid */
- port->updateMethod.searchTreePendingWrite = TRUE;
- }
- else
- {
- portsLeft = FALSE;
- IX_ETH_DB_UPDATE_TRACE("DB: (Update) No trees to create this round\n");
- }
- }
-
- for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
- {
- PortInfo *updatePort = &ixEthDBPortInfo[portIndex];
- if (updatePort->updateMethod.searchTreePendingWrite)
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) Starting procedure to upload new search tree (%snull) into NPE %d\n",
- updatePort->updateMethod.searchTree != NULL ? "not " : "",
- portIndex);
- updatePort->updateMethod.updateHandler(portIndex, IX_ETH_DB_FILTERING_RECORD);
- }
- }
- }
- /**
- * @brief standard NPE update handler
- *
- * @param portID id of the port to be updated
- * @param type record type to be pushed during this update
- *
- * The NPE update handler manages updating the NPE databases
- * given a certain record type.
- *
- * @internal
- */
- IX_ETH_DB_PUBLIC
- IxEthDBStatus ixEthDBNPEUpdateHandler(IxEthDBPortId portID, IxEthDBRecordType type)
- {
- UINT32 epDelta, blockCount;
- IxNpeMhMessage message;
- UINT32 treeSize = 0;
- PortInfo *port = &ixEthDBPortInfo[portID];
- /* size selection and type check */
- if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
- {
- treeSize = FULL_ELT_BYTE_SIZE;
- }
- else if (type == IX_ETH_DB_FIREWALL_RECORD)
- {
- treeSize = FULL_FW_BYTE_SIZE;
- }
- else
- {
- return IX_ETH_DB_INVALID_ARG;
- }
-
- /* serialize tree into memory */
- ixEthDBNPETreeWrite(type, treeSize, port->updateMethod.npeUpdateZone, port->updateMethod.searchTree, &epDelta, &blockCount);
- /* free internal copy */
- if (port->updateMethod.searchTree != NULL)
- {
- ixEthDBFreeMacTreeNode(port->updateMethod.searchTree);
- }
- /* forget last used search tree */
- port->updateMethod.searchTree = NULL;
- port->updateMethod.searchTreePendingWrite = FALSE;
- /* dependending on the update type we do different things */
- if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
- {
- IX_STATUS result;
- FILL_SETMACADDRESSDATABASE_MSG(message, IX_ETH_DB_PORT_ID_TO_NPE_LOGICAL_ID(portID),
- epDelta, blockCount,
- IX_OSAL_MMU_VIRT_TO_PHYS(port->updateMethod.npeUpdateZone));
- IX_ETHDB_SEND_NPE_MSG(IX_ETH_DB_PORT_ID_TO_NPE(portID), message, result);
- if (result == IX_SUCCESS)
- {
- IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) Finished downloading NPE tree on port %d\n", portID);
- }
- else
- {
- ixEthDBPortInfo[portID].agingEnabled = FALSE;
- ixEthDBPortInfo[portID].updateMethod.updateEnabled = FALSE;
- ixEthDBPortInfo[portID].updateMethod.userControlled = TRUE;
- ERROR_LOG("EthDB: (PortUpdate) disabling aging and updates on port %d (assumed dead)\n", portID);
- ixEthDBDatabaseClear(portID, IX_ETH_DB_ALL_RECORD_TYPES);
- return IX_ETH_DB_FAIL;
- }
- return IX_ETH_DB_SUCCESS;
- }
- else if (type == IX_ETH_DB_FIREWALL_RECORD)
- {
- return ixEthDBFirewallUpdate(portID, port->updateMethod.npeUpdateZone, epDelta);
- }
-
- return IX_ETH_DB_INVALID_ARG;
- }
- /**
- * @brief queries the database for a set of records to be inserted into a given tree
- *
- * @param searchTree pointer to a tree where insertions will be performed; can be NULL
- * @param query set of ports that a database record must match to be inserted into the tree
- *
- * The query method browses through the database, extracts all the descriptors matching
- * the given query parameter and inserts them into the given learning tree.
- * Note that this is an append procedure, the given tree needs not to be empty.
- * A "descriptor matching the query" is a descriptor whose port id is in the query map.
- * If the given tree is empty (NULL) a new tree is created and returned.
- *
- * @return the tree root
- *
- * @internal
- */
- IX_ETH_DB_PUBLIC
- MacTreeNode* ixEthDBQuery(MacTreeNode *searchTree, IxEthDBPortMap query, IxEthDBRecordType recordFilter, UINT32 maxEntries)
- {
- HashIterator iterator;
- UINT32 entryCount = 0;
- /* browse database */
- BUSY_RETRY(ixEthDBInitHashIterator(&dbHashtable, &iterator));
- while (IS_ITERATOR_VALID(&iterator))
- {
- MacDescriptor *descriptor = (MacDescriptor *) iterator.node->data;
- IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) querying [%s]:%d on port map ... ",
- mac2string(descriptor->macAddress),
- descriptor->portID);
- if ((descriptor->type & recordFilter) != 0
- && IS_PORT_INCLUDED(descriptor->portID, query))
- {
- MacDescriptor *descriptorClone = ixEthDBCloneMacDescriptor(descriptor);
- IX_ETH_DB_UPDATE_TRACE("match\n");
- if (descriptorClone != NULL)
- {
- /* add descriptor to tree */
- searchTree = ixEthDBTreeInsert(searchTree, descriptorClone);
- entryCount++;
- }
- }
- else
- {
- IX_ETH_DB_UPDATE_TRACE("no match\n");
- }
- if (entryCount < maxEntries)
- {
- /* advance to the next record */
- BUSY_RETRY(ixEthDBIncrementHashIterator(&dbHashtable, &iterator));
- }
- else
- {
- /* the NPE won't accept more entries so we can stop now */
- ixEthDBReleaseHashIterator(&iterator);
- IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) number of elements reached maximum supported by port\n");
- break;
- }
- }
- IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) query inserted %d records in the search tree\n", entryCount);
- return ixEthDBTreeRebalance(searchTree);
- }
- /**
- * @brief inserts a mac descriptor into an tree
- *
- * @param searchTree tree where the insertion is to be performed (may be NULL)
- * @param descriptor descriptor to insert into tree
- *
- * @return the tree root
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- MacTreeNode* ixEthDBTreeInsert(MacTreeNode *searchTree, MacDescriptor *descriptor)
- {
- MacTreeNode *currentNode = searchTree;
- MacTreeNode *insertLocation = NULL;
- MacTreeNode *newNode;
- INT32 insertPosition = RIGHT;
- if (descriptor == NULL)
- {
- return searchTree;
- }
- /* create a new node */
- newNode = ixEthDBAllocMacTreeNode();
- if (newNode == NULL)
- {
- /* out of memory */
- ERROR_LOG("Warning: ixEthDBAllocMacTreeNode returned NULL in file %s:%d (out of memory?)\n", __FILE__, __LINE__);
- ixEthDBFreeMacDescriptor(descriptor);
- return NULL;
- }
- /* populate node */
- newNode->descriptor = descriptor;
- /* an empty initial tree is a special case */
- if (searchTree == NULL)
- {
- return newNode;
- }
- /* get insertion location */
- while (insertLocation == NULL)
- {
- MacTreeNode *nextNode;
- /* compare given key with current node key */
- insertPosition = ixEthDBAddressCompare(descriptor->macAddress, currentNode->descriptor->macAddress);
- /* navigate down */
- if (insertPosition == RIGHT)
- {
- nextNode = currentNode->right;
- }
- else if (insertPosition == LEFT)
- {
- nextNode = currentNode->left;
- }
- else
- {
- /* error, duplicate key */
- ERROR_LOG("Warning: trapped insertion of a duplicate MAC address in an NPE search tree\n");
- /* this will free the MAC descriptor as well */
- ixEthDBFreeMacTreeNode(newNode);
- return searchTree;
- }
- /* when we can no longer dive through the tree we found the insertion place */
- if (nextNode != NULL)
- {
- currentNode = nextNode;
- }
- else
- {
- insertLocation = currentNode;
- }
- }
- /* insert node */
- if (insertPosition == RIGHT)
- {
- insertLocation->right = newNode;
- }
- else
- {
- insertLocation->left = newNode;
- }
- return searchTree;
- }
- /**
- * @brief balance a tree
- *
- * @param searchTree tree to balance
- *
- * Converts a tree into a balanced tree and returns the root of
- * the balanced tree. The resulting tree is <i>route balanced</i>
- * not <i>perfectly balanced</i>. This makes no difference to the
- * average tree search time which is the same in both cases, O(log2(n)).
- *
- * @return root of the balanced tree or NULL if there's no memory left
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- MacTreeNode* ixEthDBTreeRebalance(MacTreeNode *searchTree)
- {
- MacTreeNode *pseudoRoot = ixEthDBAllocMacTreeNode();
- UINT32 size;
- if (pseudoRoot == NULL)
- {
- /* out of memory */
- return NULL;
- }
- pseudoRoot->right = searchTree;
- ixEthDBRebalanceTreeToVine(pseudoRoot, &size);
- ixEthDBRebalanceVineToTree(pseudoRoot, size);
- searchTree = pseudoRoot->right;
- /* remove pseudoRoot right branch, otherwise it will free the entire tree */
- pseudoRoot->right = NULL;
- ixEthDBFreeMacTreeNode(pseudoRoot);
- return searchTree;
- }
- /**
- * @brief converts a tree into a vine
- *
- * @param root root of tree to convert
- * @param size depth of vine (equal to the number of nodes in the tree)
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- void ixEthDBRebalanceTreeToVine(MacTreeNode *root, UINT32 *size)
- {
- MacTreeNode *vineTail = root;
- MacTreeNode *remainder = vineTail->right;
- MacTreeNode *tempPtr;
- *size = 0;
- while (remainder != NULL)
- {
- if (remainder->left == NULL)
- {
- /* move tail down one */
- vineTail = remainder;
- remainder = remainder->right;
- (*size)++;
- }
- else
- {
- /* rotate around remainder */
- tempPtr = remainder->left;
- remainder->left = tempPtr->right;
- tempPtr->right = remainder;
- remainder = tempPtr;
- vineTail->right = tempPtr;
- }
- }
- }
- /**
- * @brief converts a vine into a balanced tree
- *
- * @param root vine to convert
- * @param size depth of vine
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- void ixEthDBRebalanceVineToTree(MacTreeNode *root, UINT32 size)
- {
- UINT32 leafCount = size + 1 - (1 << ixEthDBRebalanceLog2Floor(size + 1));
- ixEthDBRebalanceCompression(root, leafCount);
- size = size - leafCount;
- while (size > 1)
- {
- ixEthDBRebalanceCompression(root, size / 2);
- size /= 2;
- }
- }
- /**
- * @brief compresses a vine/tree stage into a more balanced vine/tree
- *
- * @param root root of the tree to compress
- * @param count number of "spine" nodes
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- void ixEthDBRebalanceCompression(MacTreeNode *root, UINT32 count)
- {
- MacTreeNode *scanner = root;
- MacTreeNode *child;
- UINT32 local_index;
- for (local_index = 0 ; local_index < count ; local_index++)
- {
- child = scanner->right;
- scanner->right = child->right;
- scanner = scanner->right;
- child->right = scanner->left;
- scanner->left = child;
- }
- }
- /**
- * @brief computes |_log2(x)_| (a.k.a. floor(log2(x)))
- *
- * @param x number to compute |_log2(x)_| for
- *
- * @return |_log2(x)_|
- *
- * @internal
- */
- IX_ETH_DB_PRIVATE
- UINT32 ixEthDBRebalanceLog2Floor(UINT32 x)
- {
- UINT32 log = 0;
- UINT32 val = 1;
- while (val < x)
- {
- log++;
- val <<= 1;
- }
- return val == x ? log : log - 1;
- }
|