1111
1212class SimpleMeshTables : public mesh ::MeshTables {
1313 uint8_t _hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE];
14- int _next_idx;
14+ uint32_t _last_seen[MAX_PACKET_HASHES]; // timestamp for LRU eviction
1515 uint32_t _acks[MAX_PACKET_ACKS];
1616 int _next_ack_idx;
1717 uint32_t _direct_dups, _flood_dups;
1818
1919public:
20- SimpleMeshTables () {
20+ SimpleMeshTables () {
2121 memset (_hashes, 0 , sizeof (_hashes));
22- _next_idx = 0 ;
22+ memset (_last_seen, 0 , sizeof (_last_seen)) ;
2323 memset (_acks, 0 , sizeof (_acks));
2424 _next_ack_idx = 0 ;
2525 _direct_dups = _flood_dups = 0 ;
@@ -28,13 +28,26 @@ class SimpleMeshTables : public mesh::MeshTables {
2828#ifdef ESP32
2929 void restoreFrom (File f) {
3030 f.read (_hashes, sizeof (_hashes));
31- f.read ((uint8_t *) &_next_idx, sizeof (_next_idx));
31+ int dummy_idx;
32+ f.read ((uint8_t *) &dummy_idx, sizeof (dummy_idx)); // legacy, ignore
3233 f.read ((uint8_t *) &_acks[0 ], sizeof (_acks));
3334 f.read ((uint8_t *) &_next_ack_idx, sizeof (_next_ack_idx));
35+ // Treat restored hashes as just seen - give them fresh timestamps
36+ uint32_t now = millis ();
37+ const uint8_t * sp = _hashes;
38+ for (int i = 0 ; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
39+ // Check if slot has data (not all zeros)
40+ bool empty = true ;
41+ for (int j = 0 ; j < MAX_HASH_SIZE && empty; j++) {
42+ if (sp[j] != 0 ) empty = false ;
43+ }
44+ _last_seen[i] = empty ? 0 : now;
45+ }
3446 }
3547 void saveTo (File f) {
3648 f.write (_hashes, sizeof (_hashes));
37- f.write ((const uint8_t *) &_next_idx, sizeof (_next_idx));
49+ int dummy_idx = 0 ;
50+ f.write ((const uint8_t *) &dummy_idx, sizeof (dummy_idx)); // legacy format
3851 f.write ((const uint8_t *) &_acks[0 ], sizeof (_acks));
3952 f.write ((const uint8_t *) &_next_ack_idx, sizeof (_next_ack_idx));
4053 }
@@ -45,7 +58,7 @@ class SimpleMeshTables : public mesh::MeshTables {
4558 uint32_t ack;
4659 memcpy (&ack, packet->payload , 4 );
4760 for (int i = 0 ; i < MAX_PACKET_ACKS; i++) {
48- if (ack == _acks[i]) {
61+ if (ack == _acks[i]) {
4962 if (packet->isRouteDirect ()) {
5063 _direct_dups++; // keep some stats
5164 } else {
@@ -54,29 +67,45 @@ class SimpleMeshTables : public mesh::MeshTables {
5467 return true ;
5568 }
5669 }
57-
70+
5871 _acks[_next_ack_idx] = ack;
59- _next_ack_idx = (_next_ack_idx + 1 ) % MAX_PACKET_ACKS; // cyclic table
72+ _next_ack_idx = (_next_ack_idx + 1 ) % MAX_PACKET_ACKS; // cyclic table
6073 return false ;
6174 }
6275
76+ uint32_t now = millis ();
6377 uint8_t hash[MAX_HASH_SIZE];
6478 packet->calculatePacketHash (hash);
6579
80+ int oldest_idx = 0 ;
81+ uint32_t oldest_age = 0 ;
82+
6683 const uint8_t * sp = _hashes;
6784 for (int i = 0 ; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
68- if (memcmp (hash, sp, MAX_HASH_SIZE) == 0 ) {
85+ uint32_t age = now - _last_seen[i];
86+
87+ if (memcmp (hash, sp, MAX_HASH_SIZE) == 0 && _last_seen[i] != 0 ) {
88+ // Match found - refresh timestamp (LRU touch) and return true
89+ _last_seen[i] = now;
6990 if (packet->isRouteDirect ()) {
7091 _direct_dups++; // keep some stats
7192 } else {
7293 _flood_dups++;
7394 }
7495 return true ;
7596 }
97+
98+ // Track oldest entry for LRU eviction
99+ if (age > oldest_age) {
100+ oldest_age = age;
101+ oldest_idx = i;
102+ }
76103 }
77104
78- memcpy (&_hashes[_next_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
79- _next_idx = (_next_idx + 1 ) % MAX_PACKET_HASHES; // cyclic table
105+ // Not found - evict oldest (LRU)
106+ int insert_idx = oldest_idx;
107+ memcpy (&_hashes[insert_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
108+ _last_seen[insert_idx] = now;
80109 return false ;
81110 }
82111
@@ -85,7 +114,7 @@ class SimpleMeshTables : public mesh::MeshTables {
85114 uint32_t ack;
86115 memcpy (&ack, packet->payload , 4 );
87116 for (int i = 0 ; i < MAX_PACKET_ACKS; i++) {
88- if (ack == _acks[i]) {
117+ if (ack == _acks[i]) {
89118 _acks[i] = 0 ;
90119 break ;
91120 }
@@ -96,8 +125,9 @@ class SimpleMeshTables : public mesh::MeshTables {
96125
97126 uint8_t * sp = _hashes;
98127 for (int i = 0 ; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
99- if (memcmp (hash, sp, MAX_HASH_SIZE) == 0 ) {
128+ if (memcmp (hash, sp, MAX_HASH_SIZE) == 0 ) {
100129 memset (sp, 0 , MAX_HASH_SIZE);
130+ _last_seen[i] = 0 ;
101131 break ;
102132 }
103133 }
0 commit comments