How to mock directory-based sharding in Python
Simulates distributing files into logical shards using a deterministic hash of each filename, mocking how a database might shard rows across nodes.
Python code
42 linesimport os
import hashlib
from collections import defaultdict
from pathlib import Path
def get_shard_for_key(key: str, num_shards: int) -> int:
"""Return a deterministic shard index (0..num_shards-1) for a key."""
digest = hashlib.md5(key.encode('utf-8')).hexdigest()
return int(digest, 16) % num_shards
def distribute_files_to_shards(source_dir: str, num_shards: int) -> dict:
"""Distribute files from a flat source directory into logical shards."""
shard_buckets = defaultdict(list)
source_path = Path(source_dir)
if not source_path.is_dir():
raise ValueError(f"Not a directory: {source_path}")
for file_path in source_path.iterdir():
if not file_path.is_file():
continue
filename = file_path.name
shard_index = get_shard_for_key(filename, num_shards)
shard_buckets[shard_index].append(filename)
return dict(sorted(shard_buckets.items()))
if __name__ == "__main__":
demo_dir = Path("./data")
demo_dir.mkdir(exist_ok=True)
for name in ("alice.csv", "bob.txt", "carol.log", "dave.json",
"eve.txt", "frank.csv", "grace.md", "heidi.log"):
(demo_dir / name).write_text("sample content\n")
shards = distribute_files_to_shards(str(demo_dir), num_shards=3)
for shard_id, files in shards.items():
print(f"Shard {shard_id}: {', '.join(files)}")
Output
Shard 0: alice.csv, carol.log, eve.txt
Shard 1: bob.txt, frank.csv, heidi.log
Shard 2: dave.json, grace.md
How it works
get_shard_for_key hashes the filename with MD5, converts the hex digest to an integer, and modulates by the shard count — matching how many databases pick a node for a row key. distribute_files_to_shards walks a directory, collects only regular files, and buckets them into a defaultdict keyed by shard index. Sorting the dict produces stable, readable output. This lightweight pattern is a useful prototype for testing partition logic before wiring up a real database.
Common mistakes
- Using a weak hash like `hash()` that is randomized per process and breaks determinism
- Forgetting to skip subdirectories, which pollutes shard buckets with non-file entries
- Hard-coding the shard count instead of passing it as a parameter, making scale tests awkward
Variations
- Use `struct.unpack` on the digest bytes for a slightly faster arithmetic path
- Replace MD5 with SHA-256 if your mock needs to mirror a security-conscious real system
Real-world use cases
- Prototyping a partition key strategy in a design doc before implementing it in PostgreSQL or MySQL.
- Building a quick load-balancing simulation for a file-processing pipeline across worker nodes.
- Testing an ETL tool's expected file-to-shard mapping without spinning up an actual cluster.
Sponsored
More from Database scaling & optimization
- Approximate Count with HyperLogLog in Python medium
- B-Tree Insert and In-Order Traversal in Python hard
- Broadcast a Small Reference Table in Python easy
- Build a Full Text Search Index in Python medium
- Build a Partial Index Mock in Python for Database Filtering easy
- Composite index leftmost prefix in Python medium
Keep learning
Related tutorials and quizzes for this topic.