/// Index the header in the HPACK table. pubfn index(&mutself, header: Header) -> Index { // Check the static table let statik = index_static(&header);
// Don't index certain headers. This logic is borrowed from nghttp2. if header.skip_value_index() { // Right now, if this is true, the header name is always in the // static table. At some point in the future, this might not be true // and this logic will need to be updated.
debug_assert!(statik.is_some(), "skip_value_index requires a static name",); return Index::new(statik, header);
}
// If the header is already indexed by the static table, return that iflet Some((n, true)) = statik { return Index::Indexed(n, header);
}
// Don't index large headers if header.len() * 4 > self.max_size * 3 { return Index::new(statik, header);
}
if header.len() + self.size < self.max_size || !header.is_sensitive() { // Only grow internal storage if needed self.reserve_one();
}
ifself.indices.is_empty() { // If `indices` is not empty, then it is impossible for all // `indices` entries to be `Some`. So, we only need to check for the // empty case. return Index::new(statik, header);
}
// Start at the ideal position, checking all slots
probe_loop!(probe < self.indices.len(), { iflet Some(pos) = self.indices[probe] { // The slot is already occupied, but check if it has a lower // displacement. let their_dist = probe_distance(self.mask, pos.hash, probe);
let slot_idx = pos.index.wrapping_add(self.inserted);
// There already is a match for the given header name. Check if a value // matches. The header will also only be inserted if the table is not at // capacity. loop { // Compute the real index into the VecDeque let real_idx = index.wrapping_add(self.inserted);
ifself.slots[real_idx].header.value_eq(&header) { // We have a full match! return Index::Indexed(real_idx + DYN_OFFSET, header);
}
iflet Some(next) = self.slots[real_idx].next {
index = next; continue;
}
if header.is_sensitive() { // Should we assert this? // debug_assert!(statik.is_none()); return Index::Name(real_idx + DYN_OFFSET, header);
}
self.update_size(header.len(), Some(index));
// Insert the new header self.insert(header, hash);
// Recompute real_idx as it just changed. let new_real_idx = index.wrapping_add(self.inserted);
// The previous node in the linked list may have gotten evicted // while making room for this header. if new_real_idx < self.slots.len() { let idx = 0usize.wrapping_sub(self.inserted);
self.slots[new_real_idx].next = Some(idx);
}
debug_assert!(self.assert_valid_state("bottom"));
// Even if the previous header was evicted, we can still reference // it when inserting the new one... returniflet Some(n) = statik { // If name is in static table, use it instead
Index::InsertedValue(n, 0)
} else {
Index::InsertedValue(real_idx + DYN_OFFSET, 0)
};
}
}
// Passing in `usize::MAX` for prev_idx since there is no previous // header in this case. ifself.update_size(header.len(), None) { while dist != 0 { let back = probe.wrapping_sub(1) & self.mask;
// Shifts all indices that were displaced by the header that has just been // removed. fn remove_phase_two(&mutself, probe: usize) { letmut last_probe = probe; letmut probe = probe + 1;
// visit the entries in an order where we can simply reinsert them // into self.indices without any bucket stealing. let old_indices = mem::replace(&mutself.indices, vec![None; new_raw_cap]); self.mask = new_raw_cap.wrapping_sub(1);
for &pos in &old_indices[first_ideal..] { self.reinsert_entry_in_order(pos);
}
for &pos in &old_indices[..first_ideal] { self.reinsert_entry_in_order(pos);
}
debug_assert!({ let them = self.indices[probe].unwrap(); let their_distance = probe_distance(self.mask, them.hash, probe); let our_distance = probe_distance(self.mask, pos.hash, probe);
#[cfg(test)] fn assert_valid_state(&self, _msg: &'static str) -> bool { /* // Checks that the internal map structure is valid // // Ensure all hash codes in indices match the associated slot forposin&self.indices{ ifletSome(pos)=*pos{ letreal_idx=pos.index.wrapping_add(self.inserted);
// First, see if the slot is indexed for(i,pos)inself.indices.iter().enumerate(){ ifletSome(pos)=*pos{ letreal_idx=pos.index.wrapping_add(self.inserted); ifreal_idx==index{ indexed=Some(i); // Already know that there is no dup, so break break; } } }
ifletSome(actual)=indexed{ // Ensure that it is accessible.. letdesired=desired_pos(self.mask,slot.hash); letmutprobe=desired; letmutdist=0;
dist+=1; }); }else{ // There is exactly one next link letcnt=self.slots.iter().map(|s|s.next) .filter(|n|*n==Some(index.wrapping_sub(self.inserted))) .count();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.