Class LevelDBStorage

java.lang.Object
com.privatechain.storage.leveldb.LevelDBStorage
All Implemented Interfaces:
BlockchainStorage, AutoCloseable

public final class LevelDBStorage extends Object implements BlockchainStorage, AutoCloseable
Crash-safe, persistent BlockchainStorage implementation backed by LevelDB.

LevelDB is a sorted key-value store with write-ahead logging (WAL) that guarantees atomicity and crash-recovery (NFR-REL-01). Each block is stored under a big-endian 4-byte integer key equal to its index, serialized to JSON via BlockSerializer.

Key layout

 Key  : big-endian 4-byte block index  (e.g., block 7 → 0x00_00_00_07)
 Value: UTF-8 JSON of the Block object
 

Using numeric big-endian keys ensures LevelDB's lexicographic ordering matches the natural block order, making loadAll() a single sequential scan without any sorting overhead.

Thread safety

Concurrent reads use the read lock; all writes acquire the exclusive write lock. The underlying LevelDB instance is thread-safe for concurrent reads once opened, but we add our own ReentrantReadWriteLock to serialize writes and guard against concurrent close operations.

Lifecycle

Instantiate once via the constructor, inject into BlockchainConfig, and call close() when the node shuts down to release the LevelDB file lock. Failing to call close() will leave a LOCK file and prevent other processes from opening the same database directory.

Usage


 try (LevelDBStorage storage = new LevelDBStorage("/data/chain")) {
     BlockchainNode node = BlockchainConfig.builder()
         .storage(storage)
         .build();
     node.start();
     // ...
 }
 
Since:
1.0.0
See Also:
  • Constructor Details

    • LevelDBStorage

      public LevelDBStorage(String dataDirectory)
      Opens (or creates) a LevelDB database at the given directory path.

      If the directory does not exist it will be created automatically by LevelDB. If the database is already locked by another process an exception is thrown immediately rather than blocking.

      Parameters:
      dataDirectory - path to the directory where LevelDB files will be stored
      Throws:
      NullPointerException - if dataDirectory is null
      IllegalArgumentException - if dataDirectory is blank
      BlockValidationException - if the database cannot be opened
  • Method Details

    • saveBlock

      public void saveBlock(Block block)
      Persists a block atomically using a LevelDB WriteBatch.

      Using a write batch guarantees that the block is either fully written or not written at all, satisfying the atomicity requirement of BlockchainStorage.saveBlock(com.privatechain.core.model.Block).

      Specified by:
      saveBlock in interface BlockchainStorage
      Parameters:
      block - the block to persist (non-null)
      Throws:
      NullPointerException - if block is null
      BlockValidationException - if the write fails
    • loadBlock

      public Block loadBlock(int index)
      Retrieves a block by its index.
      Specified by:
      loadBlock in interface BlockchainStorage
      Parameters:
      index - block index (≥ 0)
      Returns:
      the deserialized Block
      Throws:
      NoSuchElementException - if no block exists at index
      BlockValidationException - if deserialization or hash verification fails
    • loadBlockByHash

      public Optional<Block> loadBlockByHash(String hash)
      Searches for a block by its SHA-256 hash.

      Because LevelDB is indexed by block index (not hash), this is a sequential scan. For production chains with millions of blocks, consider maintaining a secondary index; for the current milestone this linear scan is sufficient.

      Specified by:
      loadBlockByHash in interface BlockchainStorage
      Parameters:
      hash - hex-encoded block hash (non-null)
      Returns:
      an Optional containing the matching block, or empty if absent
      Throws:
      NullPointerException - if hash is null
    • loadAll

      public List<Block> loadAll()
      Returns all stored blocks in ascending index order.

      Leverages LevelDB's lexicographic ordering of big-endian keys to perform a single sequential forward scan without sorting.

      Specified by:
      loadAll in interface BlockchainStorage
      Returns:
      non-null, ordered list (maybe empty)
    • exists

      public boolean exists(String hash)
      Returns true if a block with the given hash exists.
      Specified by:
      exists in interface BlockchainStorage
      Parameters:
      hash - hex-encoded block hash (non-null)
      Returns:
      true if present
      Throws:
      NullPointerException - if hash is null
    • chainHeight

      public int chainHeight()
      Returns the number of stored blocks by counting block-keyed entries.
      Specified by:
      chainHeight in interface BlockchainStorage
      Returns:
      block count (≥ 0)
    • deleteAll

      public void deleteAll()
      Removes all block entries from the LevelDB store.

      Warning: This is irreversible. Intended for testing and chain-reset scenarios only.

      Specified by:
      deleteAll in interface BlockchainStorage
    • close

      public void close()
      Closes the LevelDB database and releases the file lock.

      Must be called when the owning BlockchainNode stops to prevent a stale LOCK file from blocking subsequent opens. Idempotent — repeated calls after the first are silently ignored.

      Specified by:
      close in interface AutoCloseable
      Throws:
      BlockValidationException - if closing the database fails
    • toString

      public String toString()
      Returns a human-readable description of this storage instance.
      Overrides:
      toString in class Object
      Returns:
      string representation