Transactional File System

How to design a transaction system? I've a cli that is supposed to create a bunch of files inside a given directory how to make it so that once it fails writing any file the previosuly written files will be rejected as well?

To implement a transactional file system in your CLI where all writes succeed or none are kept, you need to simulate atomic behavior—like in databases—since the file system itself isn't transactional.

Here's a simple, robust strategy:


✅ Approach: Temporary Directory + Atomic Rename

  1. Create a temporary directory inside the target directory.

  2. Write all files into the temp directory.

  3. If all writes succeed, atomically move/rename files from temp to the destination.

  4. If any write fails, delete the temp directory.

  5. This way, the destination remains unchanged unless everything succeeds.


🛠️ Implementation Sketch (Python Example)

python
import os import shutil import tempfile def write_transactional_files(destination_dir, files_to_write): """ files_to_write: List of (filename, content) """ try: temp_dir = tempfile.mkdtemp(dir=destination_dir) # Step 1: Write all files to temp dir for filename, content in files_to_write: temp_path = os.path.join(temp_dir, filename) with open(temp_path, 'w') as f: f.write(content) # Step 2: Move each file from temp to destination for filename, _ in files_to_write: src = os.path.join(temp_dir, filename) dst = os.path.join(destination_dir, filename) shutil.move(src, dst) except Exception as e: print(f"Error occurred: {e}") print("Rolling back...") shutil.rmtree(temp_dir, ignore_errors=True) return False # Clean up temp dir if empty shutil.rmtree(temp_dir, ignore_errors=True) return True

🔒 Optional Enhancements

  • Use file locks if there's a chance of concurrency.

  • Use checksum validation before replacing existing files.

  • Log rollback details for debugging or audit.


Would you like a version of this in another language (like Rust, Go, Node.js)?

implement the node js code

Here's a clean Node.js implementation of a transactional file writing system using a temporary directory and fs.promises for async/await support:


📦 writeTransactionalFiles.js

js
const fs = require('fs').promises; const path = require('path'); const os = require('os'); async function writeTransactionalFiles(destinationDir, filesToWrite) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'txn-')); try { // Step 1: Write all files to the temp directory for (const { filename, content } of filesToWrite) { const tempFilePath = path.join(tempDir, filename); await fs.mkdir(path.dirname(tempFilePath), { recursive: true }); await fs.writeFile(tempFilePath, content); } // Step 2: Move files from temp to destination directory for (const { filename } of filesToWrite) { const tempFilePath = path.join(tempDir, filename); const finalPath = path.join(destinationDir, filename); await fs.mkdir(path.dirname(finalPath), { recursive: true }); await fs.rename(tempFilePath, finalPath); } // Step 3: Remove temp directory await fs.rmdir(tempDir, { recursive: true }); return true; } catch (error) { console.error('Transaction failed:', error); // Rollback: Clean up the temp directory await fs.rmdir(tempDir, { recursive: true }).catch(() => {}); return false; } }

🧪 Example Usage

js
(async () => { const success = await writeTransactionalFiles('./output', [ { filename: 'file1.txt', content: 'Hello world' }, { filename: 'file2.txt', content: 'Another file' }, // simulate error by uncommenting: // { filename: null, content: 'Invalid file' }, ]); if (success) { console.log('Transaction committed successfully.'); } else { console.log('Transaction failed and rolled back.'); } })();

🔒 Notes

  • Uses os.tmpdir() for safe, cross-platform temp directories.

  • Ensures all-or-nothing write behavior.

  • Supports subfolders (e.g., 'folder/file.txt').

Would you like a version that also backs up and restores overwritten files (for partial rollback over existing files)?

How to read more about designing such systems specially technics used within databases

Great question! Designing transactional systems—especially ones that mimic database behavior like atomicity, consistency, isolation, and durability (ACID)—is a core topic in systems design and database internals.

Here’s a roadmap to learn about transactional system design with recommended resources:


🔹 1. Understand ACID Principles

Start by learning the four key properties of transactional systems:

  • Atomicity – all or nothing

  • Consistency – valid state transitions only

  • Isolation – concurrent transactions don’t interfere

  • Durability – once committed, the change persists even after crash

📘 Resource:


🔹 2. Transaction Logs & Journaling

Learn how systems recover after failure:

  • Write-ahead logging (WAL) – log changes before applying

  • Undo/redo logs

  • Journaling in file systems (like ext4, NTFS)

📘 Resources:

  • PostgreSQL Internals: WAL explained

  • LevelDB and RocksDB source code – learn how log-structured storage engines handle atomic writes


🔹 3. Two-Phase Commit & Concurrency Control

Especially useful when coordinating across multiple systems or threads:

  • Two-Phase Commit (2PC)

  • MVCC (Multi-Version Concurrency Control)

  • Pessimistic vs Optimistic Locking

📘 Resources:

  • Martin Kleppmann’s Designing Data-Intensive Applications – highly recommended! Practical, modern, and readable.

  • Google Spanner Paper (PDF) – real-world distributed transaction design


🔹 4. File-based Transaction Patterns

For systems like your CLI:

  • Temp files + atomic rename

  • Shadow paging

  • Copy-on-write file systems (e.g., ZFS, Btrfs)

📘 Resources:


🔹 5. Hands-On Projects

Nothing beats learning by doing. Try implementing:

  • A minimal key-value store with write-ahead logging

  • A journaling system for file changes

  • A transactional memory manager in your CLI


✅ TL;DR Starter Pack

If you're looking for a focused starting point:

  1. 📘 Designing Data-Intensive Applications – Martin Kleppmann

  2. 💻 LevelDB or SQLite source code

  3. 📄 Articles on WAL, MVCC, and file system journaling

  4. 🔧 Implement a toy database with logging & recovery


Would you like a guided learning plan (like a 30-day track) based on these resources?