2Brute2Best
πŸ”₯0
P7

Design an In-Memory File System With Search & Size Visitors

Medium High-frequency interview topic Pro OnlyCompositeVisitor
⚑ 30-Second Interview Cheat SheetP7 · 45-Min Design Plan
2 Patterns Combined
1. Scope Boundaries

In a 45-minute LLD interview, the interviewer tests two classic structural/behavioral patterns: Composite (treating files and directories uniformly in a tree) and Visitor (adding arbitrary tree traversals like size calculation or extension search without polluting node classes). Scope the solution to Unix-style path resolution (/a/b/c), mkdir -p, file creation/writing, alphabetical listing, and double-dispatch visitors. Mention permissions (chmod), soft/symbolic links, and file system locking as follow-up extensions.

2. Core Noun Entities
FsNodeinterface
FileNodestateful-class
DirectoryNodestateful-class
FsVisitorinterface
3. Hotspot β†’ Pattern
Uniform treatment of files and subdirectories in path navigation β†’ Composite (FsNode base with FileNode leaf and DirectoryNode composite)
Adding new tree-traversal algorithms and operations β†’ Visitor (FsVisitor interface with double-dispatch accept/visit hooks)
01

Problem statement & clarifying requirements

Design an in-memory file system supporting files, hierarchical directories, nested path creation (mkdir -p), reading, writing, and directory listing (ls). New tree-walking operationsβ€”such as recursive size calculation and search by extensionβ€”must be added without modifying the node classes, adhering strictly to the Open-Closed Principle.

Questions you should ask the interviewer first
β€œHow are paths formatted and resolved?”

Paths use Unix-style forward slashes (e.g. /home/user/src/main.cpp). Path segments are resolved iteratively from the root directory.

β€œWhat happens if `mkdir` or `createFile` encounters an existing file along the path prefix?”

The operation aborts and returns false, preventing files from acting as directories.

β€œHow should new tree traversal operations (like calculating disk usage or exporting metadata) be introduced?”

Via the Visitor pattern, keeping tree structure classes (FileNode, DirectoryNode) closed for modification.

β€œCan directories hold both files and other directories uniformly?”

Yes, using the Composite pattern, directories store polymorphic std::unique_ptr<FsNode> children.

02

First, sketch the design yourself

Spend 5 minutes listing the classes, who owns whom, and which interface hides the part that changes.

  1. 1.

    Treat files and directories uniformly: A common base class FsNode allows directories to store collections of FsNode* without caring whether each child is a leaf or a subtree.

  2. 2.

    Separate algorithms from tree structure: Hardcoding calculateTotalSize() or searchByExtension() inside FsNode pollutes the data model with every new reporting requirement. Use the Visitor pattern.

  3. 3.

    Clean memory ownership: Let parent directories own child nodes exclusively through std::unique_ptr<FsNode>, while child nodes hold a non-owning raw back-pointer DirectoryNode* parent_ to build absolute paths.

03

How to think through this problem (5-step walkthrough)

Step 1 Β· Scope the 45-minute target & core boundary

In a 45-minute LLD interview, the interviewer tests two classic structural/behavioral patterns: Composite (treating files and directories uniformly in a tree) and Visitor (adding arbitrary tree traversals like size calculation or extension search without polluting node classes). Scope the solution to Unix-style path resolution (/a/b/c), mkdir -p, file creation/writing, alphabetical listing, and double-dispatch visitors. Mention permissions (chmod), soft/symbolic links, and file system locking as follow-up extensions.

Step 2 Β· Extract candidate nouns (and reject false classes)

Not every noun in the prompt deserves its own class. Separate dumb data structs from stateful managers, and turn trivial nouns into fields or enums.

FsNode
Abstract Interface

Abstract Composite base class declaring common node attributes (name, parent pointer, isDirectory(), size()) and the accept(FsVisitor&) hook.

FileNode
Stateful Class / Manager

Leaf Composite node storing binary/text content and file size. Dispatches visitor.visitFile(*this).

DirectoryNode
Stateful Class / Manager

Composite container node owning child nodes (std::map<std::string, std::unique_ptr<FsNode>>). Dispatches visitor.visitDirectory(*this) and propagates traversal.

FsVisitor
Abstract Interface

Double-dispatch Visitor interface declaring visitFile(const FileNode&) and visitDirectory(const DirectoryNode&).

TotalSizeVisitor / ExtensionSearchVisitor
Stateful Class / Manager

Concrete visitors encapsulating traversal operations: accumulating byte size across subtrees or filtering files by suffix.

FilePath / FileExtension
Reject as Class β†’ Field / Method

Trap noun β€” beginners often create separate FilePath, PathTokenizer, or FileExtension classes. Path splitting is easily handled by std::string_view iteration, and an extension is a simple string substring check (endsWith), not a heavyweight class.

Step 3 Β· Draft the naive design & spot what breaks

A naive implementation adds recursive methods (calculateSize(), searchExtension(), printTree()) directly to DirectoryNode and FileNode, using dynamic_cast<FileNode*> to inspect children. Every new feature (e.g. disk usage analysis, checksum calculation, backup serialization) forces modifying the core node hierarchy, violating the Open-Closed Principle and cluttering domain classes with traversal state.

Step 4 Β· Map change hotspots to design patterns
Uniform treatment of files and subdirectories in path navigation→ Composite (FsNode base with FileNode leaf and DirectoryNode composite)

Having separate collections for files_ and directories_ inside every directory requires branching logic for every lookup and listing operation.

Adding new tree-traversal algorithms and operations→ Visitor (FsVisitor interface with double-dispatch accept/visit hooks)

Hardcoding operations like recursive size calculation or file extension search inside node classes violates OCP and bloats core data structures.

Step 5 Β· Lock down C++23 ownership, invariants & concurrency
  • βœ“

    Strict hierarchical tree ownership: DirectoryNode exclusively owns its children via std::map<std::string, std::unique_ptr<FsNode>>, while children hold a non-owning raw back-pointer DirectoryNode* parent_ to build absolute paths without circular references.

  • βœ“

    Collision prevention invariant: A directory cannot contain both a file and a subdirectory with the exact same name under the same parent directory.

  • βœ“

    Double-dispatch traversal invariant: When DirectoryNode::accept(visitor) is invoked, it visits the directory itself and recursively forwards child->accept(visitor) to all owned children.

04

Entities & design patterns used

Brute2Best Pro Content

Unlock Full UML Diagram & C++23 Solution

The complete UML diagram, production-ready C++23 code, follow-up extensions, and design pitfall analysis are part of Brute2Best Pro. All 7 foundation chapters are 100% free.

All 440 visual dry runs & algorithms
Interactive step-by-step playback with pointer & array state transitions
52 comprehensive LLD chapters
Interactive UML diagrams, real-world stories (Food Delivery, Trading, RPG), and practice solutions
40 C++ basics labs & hardware memory models
Vtables, byte layouts, assembly insights, and multi-threading race conditions
Production-ready C++23 source code
Modern idioms, clean contracts, time/space complexity derivations, and interview takeaways

First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.

Systems Integration

Related C++ Systems & Algorithmic Foundations

Deep dive into underlying layers