ndn-embeds 0.1.0
Lightweight NDN protocol stack for embedded systems
Loading...
Searching...
No Matches
cs.cpp
1#include "ndn/cs.hpp"
2#include "esp_heap_caps.h"
3#include "esp_log.h"
4
5namespace ndn {
6
7namespace {
8const char* TAG = "CS";
9} // namespace
10
11// =============================================================================
12// CsEntry
13// =============================================================================
14
15bool CsEntry::isFresh(TimeMs now) const {
16 if (staleTime_ == 0) {
17 return true; // No FreshnessPeriod = always fresh
18 }
19 return now < staleTime_;
20}
21
22// =============================================================================
23// ContentStore
24// =============================================================================
25
27 if (entries_ != nullptr) {
28 heap_caps_free(entries_);
29 entries_ = nullptr;
30 }
31}
32
33Error ContentStore::init(size_t maxEntries) {
34 if (entries_ != nullptr) {
35 ESP_LOGW(TAG, "Already initialized, skipping");
36 return Error::Success; // Already initialized is not an error
37 }
38
39 const size_t allocSize = sizeof(CsEntry) * maxEntries;
40 entries_ =
41 static_cast<CsEntry*>(heap_caps_malloc(allocSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
42
43 if (entries_ == nullptr) {
44 ESP_LOGE(TAG, "Failed to allocate %zu bytes from PSRAM for %zu entries", allocSize,
45 maxEntries);
46 return Error::NoMemory;
47 }
48
49 capacity_ = maxEntries;
50 size_ = 0;
51
52 // Initialize all entries
53 for (size_t i = 0; i < capacity_; i++) {
54 entries_[i].inUse_ = false;
55 }
56
57 ESP_LOGI(TAG, "Initialized with %zu entries (%zu bytes PSRAM)", capacity_, allocSize);
58 return Error::Success;
59}
60
62 const Name& name = data.name();
63
64 // Search for existing entry (update)
65 for (size_t i = 0; i < capacity_; i++) {
66 auto& entry = entries_[i];
67 if (entry.inUse_ && entry.data_.name().equals(name)) {
68 entry.data_ = data;
69 entry.lastUsed_ = now;
70 if (data.freshnessPeriod()) {
71 entry.staleTime_ = now + *data.freshnessPeriod();
72 } else {
73 entry.staleTime_ = 0;
74 }
75 return Error::Success;
76 }
77 }
78
79 // Search for a free slot
80 CsEntry* slot = nullptr;
81 for (size_t i = 0; i < capacity_; i++) {
82 if (!entries_[i].inUse_) {
83 slot = &entries_[i];
84 break;
85 }
86 }
87
88 // If full, use LRU eviction
89 if (slot == nullptr) {
90 slot = findLruEntry();
91 if (slot != nullptr) {
92 stats_.evictions++;
93 size_--;
94 }
95 }
96
97 if (slot == nullptr) {
98 return Error::Full;
99 }
100
101 slot->data_ = data;
102 slot->lastUsed_ = now;
103 if (data.freshnessPeriod()) {
104 slot->staleTime_ = now + *data.freshnessPeriod();
105 } else {
106 slot->staleTime_ = 0;
107 }
108 slot->inUse_ = true;
109 size_++;
110 stats_.insertions++;
111
112 return Error::Success;
113}
114
115const CsEntry* ContentStore::find(const Name& name, bool mustBeFresh, TimeMs now) const {
116 for (size_t i = 0; i < capacity_; i++) {
117 const auto& entry = entries_[i];
118 if (entry.inUse_ && entry.data_.name().equals(name)) {
119 if (mustBeFresh && !entry.isFresh(now)) {
120 // Stale, do not count as cache hit
121 const_cast<Stats&>(stats_).misses++;
122 return nullptr;
123 }
124 const_cast<CsEntry&>(entry).lastUsed_ = now;
125 const_cast<Stats&>(stats_).hits++;
126 return &entry;
127 }
128 }
129 const_cast<Stats&>(stats_).misses++;
130 return nullptr;
131}
132
133void ContentStore::remove(const Name& name) {
134 for (size_t i = 0; i < capacity_; i++) {
135 auto& entry = entries_[i];
136 if (entry.inUse_ && entry.data_.name().equals(name)) {
137 entry.inUse_ = false;
138 size_--;
139 return;
140 }
141 }
142}
143
145 for (size_t i = 0; i < capacity_; i++) {
146 auto& entry = entries_[i];
147 if (entry.inUse_ && !entry.isFresh(now)) {
148 entry.inUse_ = false;
149 size_--;
150 stats_.evictions++;
151 }
152 }
153}
154
155CsEntry* ContentStore::findLruEntry() {
156 CsEntry* lru = nullptr;
157 TimeMs oldestTime = UINT64_MAX;
158
159 for (size_t i = 0; i < capacity_; i++) {
160 auto& entry = entries_[i];
161 if (entry.inUse_ && entry.lastUsed_ < oldestTime) {
162 oldestTime = entry.lastUsed_;
163 lru = &entry;
164 }
165 }
166
167 return lru;
168}
169
170} // namespace ndn
Error init(size_t maxEntries=CS_DEFAULT_ENTRIES)
Initialize the Content Store.
Definition cs.cpp:33
~ContentStore()
Destructor.
Definition cs.cpp:26
Error insert(const Data &data, TimeMs now)
Insert Data into the cache.
Definition cs.cpp:61
const CsEntry * find(const Name &name, bool mustBeFresh=false, TimeMs now=0) const
Search the cache by Name.
Definition cs.cpp:115
void remove(const Name &name)
Remove the entry with the specified Name.
Definition cs.cpp:133
void evictStale(TimeMs now)
Remove stale entries.
Definition cs.cpp:144
Content Store entry.
Definition cs.hpp:33
bool isFresh(TimeMs now) const
Check if the Data is fresh.
Definition cs.cpp:15
NDN Data packet.
Definition data.hpp:49
const Name & name() const
Get the Name (const reference)
Definition data.hpp:104
std::optional< uint32_t > freshnessPeriod() const
Get the FreshnessPeriod.
Definition data.hpp:205
NDN Name class.
Definition name.hpp:64
uint64_t TimeMs
Timestamp type (milliseconds)
Definition common.hpp:107
Error
Error codes.
Definition common.hpp:24
Content Store (CS)
CS statistics.
Definition cs.hpp:186
uint32_t evictions
Eviction count.
Definition cs.hpp:190
uint32_t insertions
Insertion count.
Definition cs.hpp:189