Bird
Raised Fist0

In-Memory File System

LLDhardInterview freq: medium
Choose your preparation mode4 modes available
๐ŸŽฏ
In-Memory File System Design
40 min ยท hard
hard

Design an in-memory file system that supports hierarchical directories and files, Unix-like permissions, symbolic links, and efficient search functionality.

  • The file system supports directories and files arranged in a tree hierarchy up to 5 levels deep.
  • Each file and directory has Unix-like permissions (read, write, execute) for owner, group, and others.
  • Symbolic links (symlinks) can point to files or directories and must be resolved correctly during search and access.
  • Search functionality must support recursive search by name with permission checks.
  • Concurrency: multiple threads may read or modify the file system concurrently.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define FileSystemEntity base abstraction
Design a base abstraction for files, directories, and symlinks that share common properties such as name, permissions, and parent directory.
๐Ÿ’ก Hint
Use an abstract class to hold shared instance state like name and permissions, since Java interfaces cannot hold fields.
abstract class FileSystemEntity(name, permissions, parent) - abstract because it holds shared instance STATE; interface cannot hold fields in Java
Mid: Identifies abstract class for shared state and behavior. Senior: Explains why interface cannot hold instance fields and how abstract class enables code reuse and encapsulation.
โš ๏ธCommon Wrong Answer
Using interface FileSystemEntity with default methods but no fields leads to duplicated state in subclasses and violates DRY.
Step 2
Model Permissions with Enum and Bitmask
Design a permission model supporting read, write, execute for owner, group, and others with efficient checks.
๐Ÿ’ก Hint
Use Java enum with bitmask flags and volatile int permissionBits for atomic permission updates.
enum Permission { READ, WRITE, EXECUTE } with volatile int permissionBits - volatile ensures visibility of permission changes across threads
Mid: Uses enum for permission types. Senior: Explains volatile ensures latest permissionBits read by all threads, preventing stale reads in concurrent access.
โš ๏ธCommon Wrong Answer
Using String or int constants for permissions causes typo bugs and no atomic visibility guarantees, leading to inconsistent permission enforcement.
Step 3
Design Directory and File classes with composition
Implement Directory and File classes extending FileSystemEntity. Directory contains children entities.
๐Ÿ’ก Hint
Use composition: Directory has Map<String, FileSystemEntity> children; synchronize methods modifying children to prevent race conditions.
composition: Directory contains Map<String, FileSystemEntity> children with synchronized add/remove methods - synchronized ensures atomic updates preventing concurrent modification exceptions
Mid: Uses composition for Directory children. Senior: Traces thread interleaving where Thread 1 adds child, Thread 2 reads children concurrently without synchronization causing ConcurrentModificationException.
โš ๏ธCommon Wrong Answer
Using unsynchronized HashMap for children leads to ConcurrentModificationException or corrupted state under concurrent modifications.
Step 4
Implement Symlink with target resolution
Design Symlink class that points to another FileSystemEntity and resolves target during access.
๐Ÿ’ก Hint
Symlink holds a reference to target path as String and resolves lazily; use synchronized resolution to avoid inconsistent target during concurrent updates.
class Symlink extends FileSystemEntity with volatile String targetPath and synchronized resolveTarget() - volatile ensures visibility of targetPath updates; synchronized prevents race during resolution
Mid: Implements Symlink with target path. Senior: Explains volatile visibility and synchronized resolution preventing stale or inconsistent target resolution under concurrent updates.
โš ๏ธCommon Wrong Answer
Storing targetPath without volatile or synchronization causes stale reads or partial updates leading to broken symlink resolution.
Step 5
Implement recursive search with permission checks
Design search method to recursively find entities by name, respecting permissions and resolving symlinks.
๐Ÿ’ก Hint
Use synchronized search method to atomically check permissions and traverse children; avoid deadlocks by acquiring locks in consistent order.
public synchronized List<FileSystemEntity> search(String name, User user) - synchronized to atomically check permissions and traverse children preventing race conditions during search
Mid: Implements recursive search with permission checks. Senior: Explains thread interleaving where concurrent modification without synchronization causes inconsistent search results or permission bypass.
โš ๏ธCommon Wrong Answer
Non-synchronized search allows concurrent modifications causing inconsistent or partial search results and potential security violations.
๐Ÿ”Œ
API Design Challenge
Design a RESTful API for the in-memory file system that allows clients to create, read, update, delete files and directories, manage permissions, create and resolve symlinks, and perform search operations.
  • Use resource-oriented endpoints such as /files/{path} and /directories/{path} with appropriate HTTP methods (GET, POST, PUT, DELETE).
  • Implement permission checks at the API layer to enforce Unix-like permissions for owner, group, and others.
  • Design query parameters for search functionality to support recursive search by name and filtering by permissions.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • abstract class FileSystemEntity with shared instance state
  • enum Permission with volatile permissionBits for concurrency
  • composition: Directory contains synchronized Map children
  • Symlink with volatile targetPath and synchronized resolution
  • synchronized recursive search with permission checks
Good to Have - 30%
  • explanation of volatile for visibility guarantees
  • deadlock avoidance strategy in recursive traversal
  • use of bitmask for efficient permission checks
  • clear lifecycle ownership in composition
  • polymorphic design enforcing Liskov Substitution Principle
Bonus - 10%
  • support for concurrent read-write locks for better concurrency
  • caching resolved symlink targets with atomic updates
  • detailed concurrency scenario tracing race conditions
  • extensibility for additional file types without modifying base classes
Using interface for FileSystemEntity leads to duplicated state and violates DRY, causing maintenance overhead and inconsistent behavior.
Using String for permissions causes typo bugs and no atomic visibility, leading to inconsistent permission enforcement and security risks.
Unsynchronized HashMap for Directory children causes ConcurrentModificationException or corrupted state under concurrent modifications, resulting in runtime errors.
Symlink targetPath without volatile or synchronization causes stale reads or partial updates leading to broken symlink resolution and inconsistent file system state.
โœ…
Model Answer
โ–ผ Reveal

    • abstract class FileSystemEntity holds shared instance state (name, permissions, parent) - interface cannot hold fields in Java
    • Permission modeled as enum with bitmask flags and volatile int permissionBits for atomic visibility
    • Directory uses composition: Map<String, FileSystemEntity> children with synchronized add/remove to prevent concurrent modification
    • Symlink stores volatile targetPath and synchronized resolveTarget() to ensure consistent resolution under concurrency
    • Recursive search method synchronized to atomically check permissions and traverse children preventing race conditions
    • Use of volatile ensures visibility of permission and symlink target updates across threads
    • Synchronized methods provide atomic check-and-set semantics preventing race conditions in modification and search
    • Avoid deadlocks by consistent lock acquisition order during recursive traversal
    • Use of composition for Directory-children relationship enforces lifecycle ownership: children cannot exist without Directory
    • Abstract class enforces Liskov Substitution Principle by allowing polymorphic treatment of files, directories, and symlinks

    Practice

    (1/5)
    1. In a parking system, should Vehicle be an abstract class or an interface if it needs to hold state like licensePlate and provide default behavior for getSize()? Why?
    easy
    A. Interface, because Java 8+ interfaces can have default methods and static fields
    B. Interface, because it allows multiple inheritance and enforces method contracts without state
    C. Abstract class, because it can hold state and provide default method implementations
    D. Abstract class, because it forces subclasses to implement all methods without defaults

    Solution

    1. Step 1: Analyze state and behavior requirements

      Since Vehicle needs to hold state like licensePlate and provide default behavior, it requires fields and method implementations.
    2. Step 2: Abstract class vs interface capabilities

      Abstract classes can have instance fields and concrete methods, while interfaces cannot hold instance state (only constants) and default methods cannot manage instance variables.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      State + default behavior -> abstract class, not interface [check]
    Hint: State needs abstract class; interfaces lack instance fields [check]
    Common Mistakes:
    2. Given a Vehicle abstraction that requires both state (e.g., speed) and behavior (e.g., accelerate()), should Vehicle be an abstract class or an interface in Java, and why?
    easy
    A. Interface, because it allows multiple inheritance and can hold state variables.
    B. Interface, because abstract classes cannot define method signatures without implementation.
    C. Abstract class, because it can hold shared state and provide default behavior implementations.
    D. Abstract class, because interfaces cannot have any methods related to behavior.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Since Vehicle needs to hold state like speed and provide default behavior like accelerate(), it requires fields and method implementations.
    2. Step 2: Choose between abstract class and interface

      Java interfaces cannot hold instance state (fields) prior to Java 8 default methods, and even then, no instance variables. Abstract classes can hold state and provide default method implementations, making them suitable here.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      State + default behavior -> abstract class, not interface [check]
    Hint: State needs fields -> abstract class; interfaces lack instance variables [check]
    Common Mistakes:
    3. A class has a private constructor and a static synchronized getInstance() method returning a single instance. Which OOP concept or pattern is applied here and why is this the correct use case?
    easy
    A. Singleton pattern ensuring only one instance exists with thread-safe access
    B. Factory Method pattern to create multiple instances with controlled access
    C. Builder pattern to construct complex objects step-by-step
    D. Prototype pattern to clone existing instances efficiently

    Solution

    1. Step 1: Identify the pattern from constructor and method

      The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single instance is created and accessed safely across threads.
    2. Step 2: Eliminate other creational patterns

      Factory Method allows multiple instances, Builder focuses on stepwise construction, and Prototype clones objects; none enforce single instance with thread safety.
    3. Final Answer:

      Option A -> Option A
    4. Quick Check:

      Private constructor + synchronized static method -> Singleton pattern [check]
    Hint: Private constructor + static synchronized method -> Singleton [check]
    Common Mistakes:
    4. The Meeting Scheduler needs to support ElectricCar attendees who require ChargingSpots. What is the minimum change to the current Java design to add this feature without modifying existing classes?
    hard
    A. Modify Attendee class to include a boolean isElectric flag and add charging logic inside existing RoomBookingManager.
    B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
    C. Create a new ElectricCarAttendee class extending Attendee and add charging spot logic inside it, modifying existing booking classes.
    D. Add charging spot support by modifying RoomBookingManager to check for electric vehicles explicitly.

    Solution

    1. Step 1: Identify extensibility without modifying existing classes

      Adding new enum values and subclass ElectricCar extends Vehicle allows extension without changing existing class code.
    2. Step 2: Update compatibility map externally

      Updating SpotCompatibility.COMPATIBILITY_MAP to include new mappings supports new vehicle and spot types without class changes.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      Extend enums + subclass + update map -> no existing class modified [check]
    Hint: Extend enums + subclass + map update -> no class changes [check]
    Common Mistakes:
    5. The system needs to support ElectricCar vehicles and ChargingSpot parking spots without modifying existing classes. What is the minimum change to the current Java design to support this extensibility?
    hard
    A. Modify Vehicle base class to add isElectric flag and add ChargingSpot as a subclass of existing Spot class.
    B. Create a new ElectricVehicle interface and make ElectricCar implement it; modify existing Vehicle class to support interface checks.
    C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; no existing classes modified.
    D. Add a boolean field 'supportsCharging' to Spot class and modify Vehicle class to check this field during parking.

    Solution

    1. Step 1: Identify extensibility without modifying existing classes

      Adding new enum values and new subclasses allows extension without changing existing class code, preserving OCP.
    2. Step 2: Why updating compatibility map is needed

      SpotCompatibility map controls which vehicle types fit which spots; updating it supports new ElectricCar and ChargingSpot types without class changes.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      New enums + subclass + compatibility map update -> no existing class changes [check]
    Hint: Extend enums + subclasses + compatibility map, no class edits [check]
    Common Mistakes:
    Recommended

    Ready to prove it?

    Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

    10 questions~5 mineasy hard