Class FileSystemStorage
- All Implemented Interfaces:
BlockchainStorage
BlockchainStorage implementation that stores each
block as a separate JSON file.
This implementation has zero native library dependencies,
making it suitable for environments where the native LevelDB or RocksDB JNI
binaries are unavailable (FR-STOR-05). It relies entirely on the JDK's
Files API.
File layout
<dataDirectory>/
├── block-0000000000.json (genesis block)
├── block-0000000001.json
├── block-0000000002.json
└── ...
Each file is named block-%010d.json (10-digit zero-padded decimal
index) so that lexicographic file-system ordering matches block order,
making loadAll() a simple directory listing without extra sorting
on any platform.
Write atomicity
Blocks are written atomically using the write-to-temp-then-rename
strategy: the JSON is first written to a .tmp file, then atomically
moved over the target via StandardCopyOption.ATOMIC_MOVE. On POSIX
systems this maps to rename(2), which is atomic — readers never see
a partial block file.
Stream resource management
Files.list(Path) returns a Stream backed by an open
directory-handle. Every call site that opens a directory stream does so
inside its own try-with-resources block so the handle is closed
immediately after use, regardless of exceptions. No helper method returns
an open stream to the caller — this is the pattern recommended by the JDK
Javadoc and required to silence static-analysis warnings.
Thread safety
Concurrent reads use the read lock; all writes acquire the exclusive write lock, satisfying FR-STOR-06.
Usage
BlockchainNode node = BlockchainConfig.builder()
.storage(new FileSystemStorage("/var/blockchain/chain"))
.build();
- Since:
- 1.0.0
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionFileSystemStorage(String dataDirectory) Constructs aFileSystemStoragerooted at the given directory path.FileSystemStorage(Path dataDirectory) Constructs aFileSystemStoragerooted at the givenPath. -
Method Summary
Modifier and TypeMethodDescriptionintReturns the number of block JSON files present in the data directory.voidDeletes all block JSON files from the data directory.booleanReturnstrueif a block with the given hash is stored.loadAll()Returns all stored blocks in ascending index order.loadBlock(int index) Retrieves a block by loading and deserializing its JSON file.loadBlockByHash(String hash) Searches for a block by its SHA-256 hash.voidPersists a block as a JSON file using an atomic write-then-rename strategy.toString()Returns a human-readable description of this storage instance.
-
Constructor Details
-
FileSystemStorage
Constructs aFileSystemStoragerooted at the given directory path.The directory is created (including all missing parents) if it does not already exist.
- Parameters:
dataDirectory- path to the directory where block files will be stored- Throws:
NullPointerException- ifdataDirectoryis nullIllegalArgumentException- ifdataDirectoryis blankBlockValidationException- if the directory cannot be created
-
FileSystemStorage
Constructs aFileSystemStoragerooted at the givenPath.- Parameters:
dataDirectory- path to the directory where block files will be stored- Throws:
NullPointerException- ifdataDirectoryis nullBlockValidationException- if the directory cannot be created
-
-
Method Details
-
saveBlock
Persists a block as a JSON file using an atomic write-then-rename strategy.- Serialize the block to JSON bytes via
BlockSerializer. - Write bytes to
block-XXXXXXXXXX.json.tmp. - Atomically rename the temp file to
block-XXXXXXXXXX.json.
- Specified by:
saveBlockin interfaceBlockchainStorage- Parameters:
block- the block to persist (non-null)- Throws:
NullPointerException- ifblockis nullBlockValidationException- if the write or rename fails
- Serialize the block to JSON bytes via
-
loadBlock
Retrieves a block by loading and deserializing its JSON file.- Specified by:
loadBlockin interfaceBlockchainStorage- Parameters:
index- block index (≥ 0)- Returns:
- the deserialized
Block - Throws:
NoSuchElementException- if no file exists forindexBlockValidationException- if deserialization or hash verification fails
-
loadBlockByHash
Searches for a block by its SHA-256 hash.Opens a directory stream inside a
try-with-resources block to guarantee the underlying directory handle is closed after the search, whether or not a match is found.- Specified by:
loadBlockByHashin interfaceBlockchainStorage- Parameters:
hash- hex-encoded block hash (non-null)- Returns:
- an
Optionalcontaining the matching block, or empty if absent - Throws:
NullPointerException- ifhashis null
-
loadAll
Returns all stored blocks in ascending index order.Opens a directory stream inside a
try-with-resources block to guarantee the underlying directory handle is closed after enumeration.The returned list is a defensive copy; mutations do not affect storage.
- Specified by:
loadAllin interfaceBlockchainStorage- Returns:
- non-null, ordered list (maybe empty)
-
exists
Returnstrueif a block with the given hash is stored.- Specified by:
existsin interfaceBlockchainStorage- Parameters:
hash- hex-encoded block hash (non-null)- Returns:
trueif a matching block exists- Throws:
NullPointerException- ifhashis null
-
chainHeight
public int chainHeight()Returns the number of block JSON files present in the data directory.Opens a directory stream inside a
try-with-resources block to guarantee the underlying directory handle is closed after counting.- Specified by:
chainHeightin interfaceBlockchainStorage- Returns:
- block count (≥ 0)
-
deleteAll
public void deleteAll()Deletes all block JSON files from the data directory.Warning: irreversible. Only
block-*.jsonfiles are removed; other files in the directory are untouched.Opens a directory stream inside a
try-with-resources block to guarantee the underlying directory handle is closed after deletion.- Specified by:
deleteAllin interfaceBlockchainStorage
-
toString
Returns a human-readable description of this storage instance.
-