# 5.21 Consistent Performance Guarantees

# 5.21 Consistent Performance Guarantees

## Problem

A hash-based structure may perform well on average but still fail in production due to unpredictable worst-case behavior. You need predictable performance bounds, not just good expected performance.

This matters in systems where latency spikes are unacceptable: real-time services, interactive applications, databases, and network-facing APIs.

## Solution

Control performance through a combination of design constraints:

```text id="p8v3ld"
- bounded load factor
- controlled collision handling
- stable hash function behavior
- fallback structures for worst cases
```

A typical hash table policy:

```text id="x2m8qf"
if load_factor > threshold:
    resize

if bucket_size > limit:
    restructure bucket
```

## Discussion

Expected O(1) performance assumes uniform hashing and bounded load factor. In practice, neither assumption is guaranteed without enforcement.

Three main sources of performance degradation exist:

1. High load factor
2. Poor hash distribution
3. Adversarial or pathological input patterns

Each must be addressed separately.

### Load factor control

The simplest guarantee is to cap the load factor:

```text id="k4n9zz"
load_factor = n / m
```

When `load_factor` exceeds a threshold, resizing is triggered. This prevents long buckets or long probe sequences from forming due to density alone.

Typical thresholds differ by strategy:

* separate chaining: higher tolerance
* open addressing: stricter threshold

### Collision containment

Even with good hashing, collisions occur. The goal is to prevent a single collision cluster from dominating runtime.

In chaining, this means keeping bucket sizes small.

In open addressing, this means preventing long probe sequences.

A common enhancement is hybrid bucket structure:

```text id="q7t2vc"
bucket:
    if size small -> list
    if size large -> tree or balanced structure
```

This bounds worst-case lookup inside a bucket.

### Hash stability and distribution

Even a well-designed table fails if the hash function is weak. A good hash function must avoid:

* clustering on structured inputs
* dependence on low-order bits only
* correlation between similar keys

For untrusted input, a seeded hash is often required to maintain statistical guarantees.

## Correctness

Performance controls do not change logical correctness. The invariants remain:

* each key is stored exactly once
* lookup finds the correct bucket or probe sequence
* equality is always checked explicitly

What changes is the guarantee on execution time, not the set of possible results.

A structure with performance safeguards still returns correct results even when it degrades to worst-case behavior. The safeguards only aim to prevent that degradation from occurring frequently.

## Complexity

Three regimes are relevant:

### Expected case

```text id="v6x1mn"
insert, lookup, delete → O(1)
```

Assumes uniform hashing and bounded load factor.

### Controlled worst case

With bucket limits or treeified buckets:

```text id="c9p3aa"
lookup → O(log b)
```

where `b` is bucket size.

### Uncontrolled worst case

Without safeguards:

```text id="m7k2ld"
lookup → O(n)
```

This occurs when many keys collide or probe sequences degenerate.

The goal of consistent performance design is to avoid entering the uncontrolled regime.

## Example

A web API stores sessions in a hash map:

```text id="s8n2pq"
session_id → session_data
```

Without safeguards, an attacker can craft session IDs that collide heavily, causing long bucket scans and request latency spikes.

With protections:

* seeded hash prevents predictable collisions
* load factor triggers resizing before saturation
* large buckets are restructured when needed

The result is stable latency even under hostile input.

## Implementation Notes

Prefer layered defenses:

1. Resize early rather than late
2. Keep load factor conservative in latency-sensitive systems
3. Use strong hashing for external input
4. Add bucket-level fallbacks for pathological clusters

Avoid relying on a single mechanism to guarantee performance.

For open addressing, monitor probe lengths in addition to load factor.

For chaining, monitor maximum bucket size rather than only average bucket size.

## Common Mistakes

Assuming average-case guarantees are sufficient in production systems.

Allowing load factor to approach 1 in open addressing.

Using weak or predictable hash functions for external inputs.

Ignoring bucket-level worst-case behavior.

Treating resizing as optional instead of a structural requirement.

Relying on randomness alone without structural safeguards.

Failing to measure tail latency or worst-case lookup time.

