A high-performance URL shortening service built in C++, implemented in 4 progressive phases — from a core in-memory engine to a full-featured service with rate limiting, analytics, and distributed hashing.
- Phase 1 — Core Engine
- Phase 2 — Rate Limiting, URL Expiry & Thread Safety
- Phase 3 — Consistent Hashing & Distribution
- Phase 4 — Advanced Features
- Getting Started
- Project Structure
Status: ✅ Complete
The foundation of the service. All components are in core/.
| File | Responsibility |
|---|---|
Idgenerator.h/.cpp |
Atomic counter-based unique ID generation (thread-safe) |
Base62Encoder.h/.cpp |
Converts numeric IDs → short alphanumeric codes ([a-zA-Z0-9]) |
LRUCache.h/.cpp |
O(1) in-memory cache with LRU eviction |
urlrespository.h / urlRepository.cpp |
Storage layer mapping short codes → long URLs |
urlshortenerservice.h / urlshortservice.cpp |
Main orchestrator |
1. shortenUrl("https://google.com")
└─> ID: 1 → Base62: "1" → store("1", "https://google.com") → return "1"
2. redirect("1")
└─> Check LRU cache → miss → fetch from repository → warm cache → return URL
- URL-safe characters only (
[a-zA-Z0-9]) - 62^7 = 3.5 trillion possible short codes
- No special characters needing URL encoding
Status: ✅ Complete
Token Bucket Algorithm — per IP address:
- Each IP gets a bucket of
maxTokens(default: 5 burst) - Tokens refill at
refillRateper second (default: 2/sec) - Request is blocked if bucket is empty
RateLimiter limiter(5.0, 2.0); // 5 burst, 2 tokens/sec refill
limiter.allowRequest("192.168.1.1"); // true or falseEach URL entry now stores an optional expiry timestamp:
// Expires in 60 seconds
service.shortenUrl("https://promo.com", 60 /*ttlSeconds*/);
// No expiry (permanent)
service.shortenUrl("https://google.com");When redirect() is called on an expired URL, it returns "" and auto-deletes the entry.
LRUCache—std::mutexon allget()/put()/remove()callsUrlRepository—std::mutexon allsave()/find()callsRateLimiter—std::mutexon bucket accessAnalyticsTracker—std::mutexon hit recording
Status: ✅ Complete
Distributes short codes across multiple storage nodes with minimal reshuffling when nodes are added/removed.
service.addNode(1);
service.addNode(2);
service.addNode(3);
service.printNodeAssignment("abc"); // → Node 2
service.printNodeAssignment("xyz"); // → Node 1Virtual nodes (default: 3 per real node) ensure even distribution.
User Request
│
▼
┌──────────────┐
│ Geo DNS │ ← Routes to nearest region
└──────────────┘
│
├──────────┬──────────┬──────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │ │ Node N │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
Status: ✅ Complete
// Use a human-readable alias instead of auto-generated code
service.shortenUrl("https://linkedin.com/in/akshay", 0, "", "akshay");
service.redirect("akshay"); // → https://linkedin.com/in/akshayDuplicate aliases are rejected with a warning.
Tracks click counts per short code. Prints a sorted report:
📊 Analytics Report (Top 5 URLs):
┌─────────────┬───────────┐
│ Short Code │ Clicks │
├─────────────┼───────────┤
│ 1 │ 25 │
│ akshay │ 5 │
│ 2 │ 8 │
└─────────────┴───────────┘
ASCII art placeholder for QR code generation. In production, integrate with libqrencode.
QRCodeStub::printQR("akshay");
// Prints ASCII QR art + full URL- C++ compiler with C++17 support (GCC 7+, Clang 5+, MSVC 2017+)
cd url-shortener-cpp
g++ -std=c++17 main.cpp core/*.cpp -o app.exe./app.exeThe demo runs all 4 phases sequentially, showing:
- Basic shorten + redirect
- LRU cache hits
- Rate limiting (blocked requests)
- URL expiry (TTL)
- Consistent hash node assignments
- Custom aliases
- QR code ASCII art
- Analytics dashboard
url-shortener-cpp/
├── core/
│ ├── Base62Encoder.h/.cpp # Phase 1 — Base62 encoding
│ ├── Idgenerator.h/.cpp # Phase 1 — Unique ID generation
│ ├── LRUCache.h/.cpp # Phase 1+2 — LRU cache (thread-safe)
│ ├── urlrespository.h # Phase 1+2 — Storage layer (with TTL)
│ ├── urlRepository.cpp # Phase 1+2 — Storage implementation
│ ├── RateLimiter.h/.cpp # Phase 2 — Token bucket rate limiter
│ ├── consistenthashing.h/.cpp # Phase 3 — Consistent hash ring
│ ├── AnalyticsTracker.h/.cpp # Phase 4 — Click analytics
│ ├── QRCodeStub.h # Phase 4 — QR code ASCII stub
│ ├── urlshortenerservice.h # All phases — Main orchestrator header
│ └── urlshortservice.cpp # All phases — Main orchestrator impl
├── main.cpp # Full demo (all 4 phases)
└── app.exe # Compiled binary
| Operation | Latency | Notes |
|---|---|---|
| Cache Hit | < 1ms | LRU in-memory |
| Cache Miss + Repo | ~1ms | In-memory repo |
| URL Creation | < 1ms | Atomic counter + Base62 |
| Rate Check | < 0.1ms | Token bucket |
Built with ❤️ and C++17