static void _athenaLRUContentStore_PurgeContentStoreEntry(AthenaLRUContentStore *impl, _AthenaLRUContentStoreEntry *storeEntry) { PARCObject *nameKey = _createHashableKey(ccnxContentObject_GetName(storeEntry->contentObject), NULL, NULL); parcHashMap_Remove(impl->tableByName, nameKey); parcObject_Release((PARCObject **) &nameKey); if (storeEntry->hasKeyId) { PARCObject *nameAndKeyIdKey = _createHashableKey(ccnxContentObject_GetName(storeEntry->contentObject), storeEntry->keyId, NULL); parcHashMap_Remove(impl->tableByNameAndKeyId, nameAndKeyIdKey); parcObject_Release((PARCObject **) &nameAndKeyIdKey); } if (storeEntry->hasContentObjectHash) { PARCObject *nameAndContentObjectHashKey = _createHashableKey( ccnxContentObject_GetName(storeEntry->contentObject), NULL, storeEntry->contentObjectHash); parcHashMap_Remove(impl->tableByNameAndObjectHash, nameAndContentObjectHashKey); parcObject_Release((PARCObject **) &nameAndContentObjectHashKey); } parcSortedList_Remove(impl->listByExpiryTime, storeEntry); parcSortedList_Remove(impl->listByRecommendedCacheTime, storeEntry); impl->currentSizeInBytes -= storeEntry->sizeInBytes; _athenaLRUContentStore_RemoveContentStoreEntryFromLRU(impl, storeEntry); impl->numEntries--; }
static CCNxContentObject * //_athenaLRUContentStore_GetMatch(AthenaContentStoreImplementation *store, const CCNxName *name, const PARCBuffer *keyIdRestriction, // const PARCBuffer *contentObjectHash) _athenaLRUContentStore_GetMatch(AthenaContentStoreImplementation *store, const CCNxInterest *interest) { CCNxContentObject *result = NULL; AthenaLRUContentStore *impl = (AthenaLRUContentStore *) store; _AthenaLRUContentStoreEntry *entry = NULL; CCNxName *name = ccnxInterest_GetName(interest); PARCBuffer *contentObjectHashRestriction = ccnxInterest_GetContentObjectHashRestriction(interest); PARCBuffer *keyIdRestriction = ccnxInterest_GetKeyIdRestriction(interest); if (contentObjectHashRestriction != NULL) { PARCObject *nameAndHashKey = _createHashableKey(name, NULL, contentObjectHashRestriction); entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByNameAndObjectHash, nameAndHashKey); parcObject_Release((PARCObject **) &nameAndHashKey); } if ((entry == NULL) && (keyIdRestriction != NULL)) { PARCObject *nameAndKeyIdKey = _createHashableKey(name, keyIdRestriction, NULL); entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByNameAndKeyId, nameAndKeyIdKey); parcObject_Release((PARCObject **) &nameAndKeyIdKey); } if (entry == NULL) { PARCObject *nameKey = _createHashableKey(name, NULL, NULL); entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByName, nameKey); parcObject_Release((PARCObject **) &nameKey); } // Matching is done. Now check for validity, if necessary. if (entry != NULL) { // We found matching content. Now make sure it's not expired before returning it. If it is expired, // remove it from the store and don't return anything. if (entry->hasExpiryTime && (entry->expiryTime < parcClock_GetTime(impl->wallClock))) { _athenaLRUContentStore_PurgeContentStoreEntry(impl, entry); entry = NULL; } // XXX: TODO: Check that the KeyId, if any, was verified. } // At this point, the cached content is considered valid for responding with. Return it. if (entry != NULL) { result = entry->contentObject; // Update LRU so that the matched entry is at the top of the list. _moveContentStoreEntryToLRUHead(impl, entry); impl->stats.numMatchHits++; } else { impl->stats.numMatchMisses++; } return result; }
static bool _athenaLRUContentStore_RemoveMatch(AthenaContentStoreImplementation *store, const CCNxName *name, const PARCBuffer *keyIdRestriction, const PARCBuffer *contentObjectHash) { AthenaLRUContentStore *impl = (AthenaLRUContentStore *) store; bool wasRemoved = false; if (contentObjectHash != NULL) { PARCObject *nameAndHashKey = _createHashableKey(name, NULL, contentObjectHash); _AthenaLRUContentStoreEntry *entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByNameAndObjectHash, nameAndHashKey); parcObject_Release((PARCObject **) &nameAndHashKey); if (entry != NULL) { _athenaLRUContentStore_PurgeContentStoreEntry(store, entry); wasRemoved = true; } } if (!wasRemoved && keyIdRestriction != NULL) { PARCObject *nameAndKeyIdKey = _createHashableKey(name, keyIdRestriction, NULL); _AthenaLRUContentStoreEntry *entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByNameAndKeyId, nameAndKeyIdKey); parcObject_Release((PARCObject **) &nameAndKeyIdKey); if (entry != NULL) { _athenaLRUContentStore_PurgeContentStoreEntry(store, entry); wasRemoved = true; } } if (!wasRemoved) { PARCObject *nameKey = _createHashableKey(name, NULL, NULL); _AthenaLRUContentStoreEntry *entry = (_AthenaLRUContentStoreEntry *) parcHashMap_Get(impl->tableByName, nameKey); parcObject_Release((PARCObject **) &nameKey); if (entry != NULL) { _athenaLRUContentStore_PurgeContentStoreEntry(store, entry); wasRemoved = true; } } return wasRemoved; }
LONGBOW_TEST_CASE(Loca, _createHashableKey_Name) { CCNxName *name1 = ccnxName_CreateFromURI("lci:/name/1"); CCNxName *name2 = ccnxName_CreateFromURI("lci:/name/2"); PARCObject *keyObj1 = _createHashableKey(name1, NULL, NULL); PARCObject *keyObj2 = _createHashableKey(name2, NULL, NULL); assertNotNull(keyObj1, "Expected non-null key object"); assertNotNull(keyObj2, "Expected non-null key object"); assertFalse(parcObject_HashCode(keyObj1) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj2) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj1) == parcObject_HashCode(keyObj2), "Expected different hashcodes"); parcObject_Release((PARCObject **) &keyObj1); parcObject_Release((PARCObject **) &keyObj2); ccnxName_Release(&name1); ccnxName_Release(&name2); }
LONGBOW_TEST_CASE(Loca, _createHashableKey_NameAndObjectHash) { // Now try with key Ids. CCNxName *name1 = ccnxName_CreateFromURI("lci:/name/1"); CCNxName *name2 = ccnxName_CreateFromURI("lci:/name/2"); PARCBuffer *objHash1 = parcBuffer_WrapCString("hash 1"); PARCBuffer *objHash2 = parcBuffer_WrapCString("hash 2"); PARCObject *keyObj1 = _createHashableKey(name1, NULL, objHash1); PARCObject *keyObj2 = _createHashableKey(name1, NULL, NULL); assertFalse(parcObject_HashCode(keyObj1) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj2) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj1) == parcObject_HashCode(keyObj2), "Expected different hashcodes"); parcObject_Release((PARCObject **) &keyObj1); parcObject_Release((PARCObject **) &keyObj2); // Different object hashes. keyObj1 = _createHashableKey(name1, NULL, objHash1); keyObj2 = _createHashableKey(name1, NULL, objHash2); assertFalse(parcObject_HashCode(keyObj1) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj2) == 0, "Expected non zero hashcode"); assertFalse(parcObject_HashCode(keyObj1) == parcObject_HashCode(keyObj2), "Expected different hashcodes"); parcObject_Release((PARCObject **) &keyObj1); parcObject_Release((PARCObject **) &keyObj2); parcBuffer_Release(&objHash1); parcBuffer_Release(&objHash2); // Now try with ccnxName_Release(&name1); ccnxName_Release(&name2); }
static bool _athenaLRUContentStore_PutLRUContentStoreEntry(AthenaContentStoreImplementation *store, const _AthenaLRUContentStoreEntry *entry) { bool result = false; AthenaLRUContentStore *impl = (AthenaLRUContentStore *) store; // Enforce capacity limit. If adding the next store item would put us over the limit, we have to remove // entrie(s) until there is room. bool isEnoughRoomInStore = true; if ((entry->sizeInBytes + impl->currentSizeInBytes) > impl->maxSizeInBytes) { isEnoughRoomInStore = _makeRoomInStore(impl, entry->sizeInBytes); } if (isEnoughRoomInStore) { _AthenaLRUContentStoreEntry *newEntry = _athenaLRUContentStoreEntry_Acquire(entry); // New entries go to the HEAD of the LRU. _addContentStoreEntryToLRUHead(impl, newEntry); // DO NOT RELEASE the newEntry after adding it to the containers. We will let the LRU be responsible for the // final release. At this point, the reference count of the new LRUContentStoreEntry is 1 and the LRU // points to it. The other containers (hashmap indices, sorted lists, etc) can acquire and release on their // own, but the LRU holds the final reference. _AthenaLRUContentStoreEntry *existingEntry = NULL; CCNxName *name = ccnxContentObject_GetName(newEntry->contentObject); if (name != NULL) { PARCObject *nameKey = _createHashableKey(name, NULL, NULL); existingEntry = _addEntryToIndexTableIfNotAlreadyInIt(impl->tableByName, nameKey, newEntry); parcObject_Release((PARCObject **) &nameKey); } if (newEntry->hasKeyId) { PARCObject *nameAndKeyIdKey = _createHashableKey(name, newEntry->keyId, NULL); existingEntry = _addEntryToIndexTableIfNotAlreadyInIt(impl->tableByNameAndKeyId, nameAndKeyIdKey, newEntry); parcObject_Release((PARCObject **) &nameAndKeyIdKey); } if (newEntry->hasContentObjectHash) { PARCObject *nameAndObjectHashKey = _createHashableKey(name, NULL, newEntry->contentObjectHash); existingEntry = _addEntryToIndexTableIfNotAlreadyInIt(impl->tableByNameAndObjectHash, nameAndObjectHashKey, newEntry); parcObject_Release((PARCObject **) &nameAndObjectHashKey); } if (existingEntry != NULL && existingEntry->indexCount < 1) { // The existing entry is in no indexes, which means it cannot be matched and serves no further purpose. // Remove it completely from all containers. //printf("Releasing previously held store entry\n"); _athenaLRUContentStore_PurgeContentStoreEntry(impl, existingEntry); } // Add the new entry to the time-ordered lists, if it has an RCT or ExpiryTime. if (newEntry->hasExpiryTime) { parcSortedList_Add(impl->listByExpiryTime, newEntry); } if (newEntry->hasRecommendedCacheTime) { parcSortedList_Add(impl->listByRecommendedCacheTime, newEntry); } impl->stats.numAdds++; impl->numEntries++; impl->currentSizeInBytes += newEntry->sizeInBytes; result = true; } return result; }