LobStorageBackend

This class stores LOB objects in the database, in tables. This is the back-end i.e. the server side of the LOB storage.

Using the system session

Why do we use the system session to store the data? Some LOB operations can take a very long time. If we did them on a normal session, we would be locking the LOB tables for long periods of time, which is extremely detrimental to the rest of the system. Perhaps when we shift to the MVStore engine, we can revisit this design decision (using the StreamStore, that is, no connection at all).

Locking

Normally, the locking order in H2 is: first lock the Session object, then lock the Database object. However, in the case of the LOB data, we are using the system session to store the data. If we locked the normal way, we see deadlocks caused by the following pattern:

  Thread 1:
     locks normal session
     locks database
     waiting to lock system session
  Thread 2:
      locks system session
      waiting to lock database.
So, in this class alone, we do two things: we have our very own dedicated session, the LOB session, and we take the locks in this order: first the Database object, and then the LOB session. Since we own the LOB session, no-one else can lock on it, and we are safe.

Methods
static void assertHoldsLock(Object lock)
Check whether this thread has synchronized on this object.
static void assertHoldsLock(Object lock)
Check whether this thread has synchronized on this object.
Parameters:
lock - the object
ValueLobDb copyLob(ValueLobDb old, int tableId, long length)
ValueLobDb copyLob(ValueLobDb old, int tableId, long length)
Value createBlob(InputStream in, long maxLength)
Value createBlob(InputStream in, long maxLength)
Value createClob(Reader reader, long maxLength)
Value createClob(Reader reader, long maxLength)
InputStream getInputStream(ValueLobDb lob, byte[] hmac, long byteCount)
InputStream getInputStream(ValueLobDb lob, byte[] hmac, long byteCount) throws IOException
void init()
void init()
boolean isReadOnly()
boolean isReadOnly()
PreparedStatement prepare(String sql)
Create a prepared statement, or re-use an existing one.
PreparedStatement prepare(String sql) throws SQLException
Create a prepared statement, or re-use an existing one.
Parameters:
sql - the SQL statement
Returns:
the prepared statement
byte[] readBlock(long block)
Read a block of data from the given LOB.
byte[] readBlock(long block) throws SQLException
Read a block of data from the given LOB.
Parameters:
block - the block number
Returns:
the block (expanded if stored compressed)
void removeAllForTable(int tableId)
void removeAllForTable(int tableId)
void removeLob(ValueLobDb lob)
void removeLob(ValueLobDb lob)
void reuse(String sql, PreparedStatement prep)
Allow to re-use the prepared statement.
void reuse(String sql, PreparedStatement prep)
Allow to re-use the prepared statement.
Parameters:
sql - the SQL statement
prep - the prepared statement
void storeBlock(long lobId, int seq, long pos, byte[] b, String compressAlgorithm)
Store a block in the LOB storage.
void storeBlock(long lobId, int seq, long pos, byte[] b, String compressAlgorithm) throws SQLException
Store a block in the LOB storage.
Parameters:
lobId - the lob id
seq - the sequence number
pos - the position within the lob
b - the data
compressAlgorithm - the compression algorithm (may be null)