You are given a simple file writer class that writes data directly to disk:
class FileWriter {
public:
// Append `data` to the file on disk immediately (no buffering).
// May be relatively slow because it calls the OS for each write.
void write(const std::string& data);
// Flush any OS-level buffers to disk.
void flush();
};
This class is already implemented for you.
Task 1: Implement a buffered file writer
Implement a BufferedFileWriter class that uses an internal memory buffer to reduce the number of calls to the underlying FileWriter:
Requirements:
-
BufferedFileWriter
should have the following public interface (you may use composition or inheritance, but composition is preferred):
class BufferedFileWriter {
public:
BufferedFileWriter(FileWriter& underlying, size_t buffer_capacity);
// Append `data` to an in-memory buffer.
// Only when certain conditions are met (e.g., the buffer is full),
// data should be flushed to the underlying FileWriter.
void write(const std::string& data);
// Force all currently buffered data to be written to the
// underlying FileWriter and then flush it to disk.
void flush();
};
-
The constructor receives a reference to an existing
FileWriter
instance and a
buffer_capacity
in bytes.
-
write
should:
-
Append
data
to an internal memory buffer.
-
If after appending, the buffer size is
greater than or equal to
buffer_capacity
, it should write the buffered data to the underlying
FileWriter
and clear the internal buffer.
-
flush
should:
-
Write any remaining data in the internal buffer to the underlying
FileWriter
(if the buffer is not empty).
-
Then call
flush()
on the underlying
FileWriter
.
-
You may assume:
-
All input strings are reasonably small compared to
buffer_capacity
.
-
Memory allocation does not fail.
-
Write a few unit tests (or describe them) to validate the behavior, including:
-
Writing data smaller than
buffer_capacity
and then calling
flush()
.
-
Writing multiple chunks that together exceed
buffer_capacity
and ensuring data is flushed at the right times.
-
Ensuring that multiple
flush()
calls with an empty buffer are safe.
You do not need to implement the real file I/O of FileWriter; only show the code for BufferedFileWriter using the given interface.
Follow-up: Make BufferedFileWriter thread-safe
Now assume that BufferedFileWriter may be used from multiple threads concurrently. Different threads may call write() and flush() at the same time.
-
Extend your design so that
BufferedFileWriter
is
thread-safe
.
-
Define what thread-safety guarantees you provide. For example, it should appear as if calls to
write()
and
flush()
from all threads are executed in some serial order, and data is not corrupted or lost.
-
Provide pseudocode (language of your choice) that shows:
-
How you protect shared state (the internal buffer and any other shared fields).
-
How
write()
and
flush()
coordinate with each other.
-
How you avoid data races and inconsistent writes.
Assume you may use standard synchronization primitives such as mutexes/locks and condition variables if needed.