From c580a00aac271a524e5a75b35f4b91c174ed227b Mon Sep 17 00:00:00 2001 From: michele papalini Date: Thu, 23 Feb 2017 17:01:34 +0100 Subject: Initial commit: sb-forwarder, metis. Change-Id: I65ee3c851a6901929ef4417ad80d34bca0dce445 Signed-off-by: michele papalini --- .../forwarder/metis/core/metis_ConnectionTable.c | 252 +++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 metis/ccnx/forwarder/metis/core/metis_ConnectionTable.c (limited to 'metis/ccnx/forwarder/metis/core/metis_ConnectionTable.c') diff --git a/metis/ccnx/forwarder/metis/core/metis_ConnectionTable.c b/metis/ccnx/forwarder/metis/core/metis_ConnectionTable.c new file mode 100644 index 00000000..9e15b30e --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/metis_ConnectionTable.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @header MetisConnectionTable + * @abstract Records all the current connections and references to them + * @discussion + * + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +struct metis_connection_table { + // The main storage table that has a Destroy method. + // The key is an unsigned int pointer. We use an unsigned int pointer + // because we want to be able to lookup by the id alone, and not have to + // have the MetisIoOperations everywhere. + PARCHashCodeTable *storageTableById; + + // The key is a MetisAddressPair + // It does not have a destroy method for the data or key, + // as they are derived from the storage table. + PARCHashCodeTable *indexByAddressPair; + + // An iterable stucture organized by connection id. The keys and + // values are the same pointers as in storageTableById, so there + // are no destructors in the tree. + // The only reason to keep this tree is so we have an iterable list + // of connections, which the hash table does not give us. + PARCTreeRedBlack *listById; +}; + +static bool +metisConnectionTable_ConnectionIdEquals(const void *keyA, const void *keyB) +{ + unsigned idA = *((unsigned *) keyA); + unsigned idB = *((unsigned *) keyB); + return (idA == idB); +} + +static int +metisConnectionTable_ConnectionIdCompare(const void *keyA, const void *keyB) +{ + unsigned idA = *((unsigned *) keyA); + unsigned idB = *((unsigned *) keyB); + if (idA < idB) { + return -1; + } + if (idA > idB) { + return +1; + } + return 0; +} + +static bool +metisConnectionTable_AddressPairEquals(const void *keyA, const void *keyB) +{ + const MetisAddressPair *pairA = (const MetisAddressPair *) keyA; + const MetisAddressPair *pairB = (const MetisAddressPair *) keyB; + + return metisAddressPair_Equals(pairA, pairB); +} + +static HashCodeType +metisConnectionTable_ConnectionIdHashCode(const void *keyA) +{ + unsigned idA = *((unsigned *) keyA); + return parcHash32_Int32(idA); +} + +static HashCodeType +metisConnectionTable_AddressPairHashCode(const void *keyA) +{ + const MetisAddressPair *pairA = (const MetisAddressPair *) keyA; + return metisAddressPair_HashCode(pairA); +} + + +static void +metisConnectionTable_ConnectionIdDestroyer(void **dataPtr) +{ + unsigned *idA = (unsigned *) *dataPtr; + parcMemory_Deallocate((void **) &idA); + *dataPtr = NULL; +} + +static void +metisConnectionTable_ConnectionDestroyer(void **dataPtr) +{ + metisConnection_Release((MetisConnection **) dataPtr); +} + +MetisConnectionTable * +metisConnectionTable_Create() +{ + size_t initialSize = 16384; + + MetisConnectionTable *conntable = parcMemory_AllocateAndClear(sizeof(MetisConnectionTable)); + assertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisConnectionTable)); + + conntable->storageTableById = parcHashCodeTable_Create_Size(metisConnectionTable_ConnectionIdEquals, + metisConnectionTable_ConnectionIdHashCode, + metisConnectionTable_ConnectionIdDestroyer, + metisConnectionTable_ConnectionDestroyer, + initialSize); + + // no key or data destroyer, this is an index into storageByid. + conntable->indexByAddressPair = parcHashCodeTable_Create_Size(metisConnectionTable_AddressPairEquals, + metisConnectionTable_AddressPairHashCode, + NULL, + NULL, + initialSize); + + conntable->listById = parcTreeRedBlack_Create(metisConnectionTable_ConnectionIdCompare, + NULL, // key free + NULL, // key copy + NULL, // value equals + NULL, // value free + NULL); // value copy + + return conntable; +} + + +void +metisConnectionTable_Destroy(MetisConnectionTable **conntablePtr) +{ + assertNotNull(conntablePtr, "Parameter must be non-null double pointer"); + assertNotNull(*conntablePtr, "Parameter must dereference to non-null pointer"); + + MetisConnectionTable *conntable = *conntablePtr; + + parcTreeRedBlack_Destroy(&conntable->listById); + parcHashCodeTable_Destroy(&conntable->indexByAddressPair); + parcHashCodeTable_Destroy(&conntable->storageTableById); + parcMemory_Deallocate((void **) &conntable); + *conntablePtr = NULL; +} + +/** + * @function metisConnectionTable_Add + * @abstract Add a connection, takes ownership of memory + * @discussion + * <#Discussion#> + * + * @param <#param1#> + */ +void +metisConnectionTable_Add(MetisConnectionTable *table, MetisConnection *connection) +{ + assertNotNull(table, "Parameter table must be non-null"); + assertNotNull(connection, "Parameter connection must be non-null"); + + unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned)); + assertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL", sizeof(unsigned)); + *connectionIdKey = metisConnection_GetConnectionId(connection); + + if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey, connection)) { + parcHashCodeTable_Add(table->indexByAddressPair, (void *) metisConnection_GetAddressPair(connection), connection); + parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection); + } else { + trapUnexpectedState("Could not add connection id %u -- is it a duplicate?", *connectionIdKey); + } +} + +/** + * @function metisConnectionTable_Remove + * @abstract Removes the connection, calling Destroy on our copy + * @discussion + * <#Discussion#> + * + * @param <#param1#> + */ +void +metisConnectionTable_Remove(MetisConnectionTable *table, const MetisConnection *connection) +{ + assertNotNull(table, "Parameter table must be non-null"); + assertNotNull(connection, "Parameter connection must be non-null"); + + unsigned connid = metisConnection_GetConnectionId(connection); + + parcTreeRedBlack_Remove(table->listById, &connid); + parcHashCodeTable_Del(table->indexByAddressPair, metisConnection_GetAddressPair(connection)); + parcHashCodeTable_Del(table->storageTableById, &connid); +} + +void +metisConnectionTable_RemoveById(MetisConnectionTable *table, unsigned id) +{ + assertNotNull(table, "Parameter table must be non-null"); + const MetisConnection *connection = metisConnectionTable_FindById(table, id); + if (connection) { + metisConnectionTable_Remove(table, connection); + } +} + +const MetisConnection * +metisConnectionTable_FindByAddressPair(MetisConnectionTable *table, const MetisAddressPair *pair) +{ + assertNotNull(table, "Parameter table must be non-null"); + return (MetisConnection *) parcHashCodeTable_Get(table->indexByAddressPair, pair); +} + +const MetisConnection * +metisConnectionTable_FindById(MetisConnectionTable *table, unsigned id) +{ + assertNotNull(table, "Parameter table must be non-null"); + return (MetisConnection *) parcHashCodeTable_Get(table->storageTableById, &id); +} + + +MetisConnectionList * +metisConnectionTable_GetEntries(const MetisConnectionTable *table) +{ + assertNotNull(table, "Parameter table must be non-null"); + MetisConnectionList *list = metisConnectionList_Create(); + + PARCArrayList *values = parcTreeRedBlack_Values(table->listById); + for (size_t i = 0; i < parcArrayList_Size(values); i++) { + MetisConnection *original = parcArrayList_Get(values, i); + metisConnectionList_Append(list, original); + } + parcArrayList_Destroy(&values); + return list; +} -- cgit 1.2.3-korg