LLD: Design S3
If you’re looking for 1:1 mentorship with a strong focus on LLD (core emphasis on Multithreading), HLD, DSA, and system design research papers, feel free to reach out.
📩 Contact: programmingappliedai@gmail.com
FR
Create buckets
Put/Get/Delete objects
Object versioning
Thread-safe (basic)
Simple APIs similar to S3
🧱 Core Entities
S3Service
├── Bucket
│ ├── ObjectKey
│ │ └── List<ObjectVersion>
🧩 Java Code (Executable LLD)
1️⃣ ObjectVersion
import java.time.Instant;
class ObjectVersion {
private final String versionId;
private final byte[] data;
private final Instant createdAt;
public ObjectVersion(String versionId, byte[] data) {
this.versionId = versionId;
this.data = data;
this.createdAt = Instant.now();
}
public String getVersionId() {
return versionId;
}
public byte[] getData() {
return data;
}
}
2️⃣ S3Object
import java.util.*;
class S3Object {
private final String key;
private final List<ObjectVersion> versions = new ArrayList<>();
public S3Object(String key) {
this.key = key;
}
public synchronized void addVersion(ObjectVersion version) {
versions.add(version);
}
public synchronized ObjectVersion getLatestVersion() {
if (versions.isEmpty()) return null;
return versions.get(versions.size() - 1);
}
public synchronized ObjectVersion getVersion(String versionId) {
return versions.stream()
.filter(v -> v.getVersionId().equals(versionId))
.findFirst()
.orElse(null);
}
}
3️⃣ Bucket
import java.util.concurrent.ConcurrentHashMap;
class Bucket {
private final String name;
private final ConcurrentHashMap<String, S3Object> objects = new ConcurrentHashMap<>();
public Bucket(String name) {
this.name = name;
}
public void putObject(String key, byte[] data) {
objects.putIfAbsent(key, new S3Object(key));
String versionId = UUID.randomUUID().toString();
objects.get(key).addVersion(new ObjectVersion(versionId, data));
}
public byte[] getObject(String key) {
S3Object obj = objects.get(key);
if (obj == null) return null;
ObjectVersion version = obj.getLatestVersion();
return version != null ? version.getData() : null;
}
public void deleteObject(String key) {
objects.remove(key);
}
}
4️⃣ S3Service (Main API)
import java.util.concurrent.ConcurrentHashMap;
class S3Service {
private final ConcurrentHashMap<String, Bucket> buckets = new ConcurrentHashMap<>();
public void createBucket(String bucketName) {
buckets.putIfAbsent(bucketName, new Bucket(bucketName));
}
public void putObject(String bucketName, String key, byte[] data) {
Bucket bucket = buckets.get(bucketName);
if (bucket == null) {
throw new RuntimeException("Bucket not found");
}
bucket.putObject(key, data);
}
public byte[] getObject(String bucketName, String key) {
Bucket bucket = buckets.get(bucketName);
if (bucket == null) return null;
return bucket.getObject(key);
}
public void deleteObject(String bucketName, String key) {
Bucket bucket = buckets.get(bucketName);
if (bucket != null) {
bucket.deleteObject(key);
}
}
}
5️⃣ Driver Code (Test)
public class Main {
public static void main(String[] args) {
S3Service s3 = new S3Service();
s3.createBucket("photos");
s3.putObject("photos", "img1.jpg", "image-data-1".getBytes());
s3.putObject("photos", "img1.jpg", "image-data-2".getBytes());
byte[] data = s3.getObject("photos", "img1.jpg");
System.out.println(new String(data));
s3.deleteObject("photos", "img1.jpg");
}
}
🔍 Key LLD Concepts Used
Encapsulation → Bucket owns objects
Concurrency →
ConcurrentHashMapVersioning → List of ObjectVersion
Single Responsibility
API-first thinking (like real S3)
🧠 Interview Extensions (Say this out loud)
If interviewer asks:
How to scale? → Partition buckets, metadata DB + object storage (SSTables)
Large files? → Multipart upload
Durability? → Replication + checksum
Auth? → IAM + signed URLs
Consistency? → Read-after-write for new objects

