Hash table index for O(1) packet history lookups (#9499)
* Use hash table for O(1) lookup of recently seen packets * Eliminate a packet lookup during deduplication * Infinite loop checks for find and remove * Consolidate conditional compilation * Exclude hash table from minimal build * Additional comment on hash table capacity * Unit tests for packet history changes * Update incorrect comment about size clamp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Const --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
co-authored by
GitHub
Copilot
Ben Meadors
parent
837637b70c
commit
83a98c81f6
@@ -28,6 +28,22 @@ class PacketHistory
|
||||
0; // Can be set in constructor, no need to recompile. Used to allocate memory for mx_recentPackets.
|
||||
PacketRecord *recentPackets = NULL; // Simple and fixed in size. Debloat.
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_PKT_HISTORY_HASH
|
||||
// Open-addressing hash table for O(1) lookup in find(), replacing the O(N) linear scan.
|
||||
// Maps (sender, id) -> index into recentPackets[]. Uses linear probing with a load factor <= 0.5.
|
||||
// The load factor invariant holds permanently: hashCapacity = 2 * nextPowerOf2(recentPacketsCapacity),
|
||||
// and at most recentPacketsCapacity entries can ever be live (one per recentPackets[] slot).
|
||||
static constexpr uint16_t HASH_EMPTY = 0xFFFF;
|
||||
uint16_t *hashIndex = NULL;
|
||||
uint32_t hashCapacity = 0; // Always a power of 2
|
||||
uint32_t hashMask = 0; // hashCapacity - 1, for fast modular indexing
|
||||
|
||||
uint32_t hashSlot(NodeNum sender, PacketId id) const;
|
||||
void hashInsert(NodeNum sender, PacketId id, uint16_t slotIdx);
|
||||
void hashRemove(NodeNum sender, PacketId id);
|
||||
void hashRebuild();
|
||||
#endif
|
||||
|
||||
/** Find a packet record in history.
|
||||
* @param sender NodeNum
|
||||
* @param id PacketId
|
||||
@@ -70,6 +86,16 @@ class PacketHistory
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole = nullptr);
|
||||
|
||||
/**
|
||||
* Check two relayers against the same packet record with a single lookup.
|
||||
* Avoids redundant find() calls when checking multiple relayers for the same (id, sender) pair.
|
||||
* @param r1Result set to true if relayer1 was a relayer
|
||||
* @param r2Result set to true if relayer2 was a relayer
|
||||
* @param r2WasSole if not nullptr, set to true if relayer2 was the sole relayer
|
||||
*/
|
||||
void checkRelayers(uint8_t relayer1, uint8_t relayer2, uint32_t id, NodeNum sender, bool *r1Result, bool *r2Result,
|
||||
bool *r2WasSole = nullptr);
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user