Skip to content

Compaction causes missing chunks and data loss #4247

@DropSnorz

Description

@DropSnorz

I'm facing a non-deterministic issue with H2 in embedded file-based mode during batch insertions. When inserting a large number of rows (e.g., 5,000+ entries) into a table, data sometimes disappears between the closing and reopening of the connection. The table structure remains, but previously inserted data may be partially or completely missing. Most of the time, referential integrity violations occur due to lost parent rows (e.g., with self-referencing foreign keys).

This issue appears:

  • Using the latest H2 2.3.232 in a Spring Boot application with database connection managed by Hibernate.
  • Across multiple operating systems (Windows 10, macOS, Ubuntu)
  • Across different kinds of hard drives and drive speeds (HDD and SSD)

This issue might be linked to other similar reports

I tried to create a simple SSCCE without success. I've troubleshooted H2 directly in the context of my application running bulk insertions.

I've quickly suspected the database compaction for the following reasons:

  • Only tables where data has been recently inserted are impacted.
  • The problem cannot be reproduced with h2 2.3.230 . In that version, the compaction does not complete in time (infinite loop). Using the version, the database seems to grow continuously without a manual call to SHUTDOWN COMPACT.
  • A bug fix has been introduced in h2 2.3.232 that fixed the infinite loop problem, and at the same time allowed the compaction to complete.
  • Disabling auto-compaction on closing with AUTO_COMPACT_FILL_RATE=0 removed the issue completely.

I've rebuilt h2 from master / 56c0b70 version 2.3.239-SNASPHOT , but the issue can still be reproduced.

For the logs, you can check this PR for reference: DropSnorz#1

I've noticed every failure occurs upon closing after a shrink/truncate operation. It was very strange as this seems to happen after any compaction loop execution on the RandomAccessStore, but I realized that some chunks were missing.

/*SQL l:80 #:1*/update file_stat set length=?,name=?,parent_id=?,parent_path=?,path=? where id=? {1: CAST(23969 AS BIGINT), 2: 'LME_MIDI', 3: CAST(11573 AS BIGINT), 4: 'C:/AudioPlugins/VST-Presets/MASSIVE Ultimate/You''re Welcome/Loopmasters Presents Electro Synths Massive Presets', 5: 'C:/AudioPlugins/VST-Presets/MASSIVE Ultimate/You''re Welcome/Loopmasters Presents Electro Synths Massive Presets/LME_MIDI', 6: CAST(11648 AS BIGINT)};
2025-06-22 20:44:56.605399+02:00 jdbc[3]: 
/*SQL */COMMIT;
2025-06-22 20:44:56.605399+02:00 jdbc[3]: 
/*SQL */COMMIT;
2025-06-22 20:44:56.605399+02:00 database: disconnecting session #3
2025-06-22 20:44:56.605399+02:00 database: closing C:/Users/Arthur/.owlplug/owlplug
2025-06-22 20:44:56.605399+02:00 database: MVStore: Increase current version to 8655
2025-06-22 20:44:56.605399+02:00 database: MVStore: store->FileStore.dropUnusedChunks()
2025-06-22 20:44:56.605399+02:00 user: FileStore : dropUnusedChunks.toBeFreedChunks 0
2025-06-22 20:44:56.606402+02:00 database: FileStore : serializeAndStore() c.id=8655 lastChunkId=8655
2025-06-22 20:44:56.606402+02:00 database: FileStore: storeBuffer() c.id=8655
2025-06-22 20:44:56.606402+02:00 database: RAS : writeChunk->writeStoreHeader()
2025-06-22 20:44:56.606402+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.606402+02:00 database: RAS header: H:2,block:41,blockSize:1000,chunk:21cf,created:19798f30e74,format:3,version:21cf,fletcher:71a310ae
2025-06-22 20:44:56.606402+02:00 database: RAS : writeChunk->shrinkStoreIfPossible()
2025-06-22 20:44:56.607400+02:00 user: MVStore: Closing MVStore
2025-06-22 20:44:56.607400+02:00 user: MVStore : Stopping FileStore
2025-06-22 20:44:56.607400+02:00 user: RAS : compactStore
// ----------------------- Beginning of the issue
// ----------------------- Chunk and version 8656 will be unrecoverable on the next database opening
2025-06-22 20:44:56.647401+02:00 database: MVStore: Increase current version to 8656
2025-06-22 20:44:56.647401+02:00 database: MVStore: store->FileStore.dropUnusedChunks()
2025-06-22 20:44:56.647401+02:00 user: FileStore : dropUnusedChunks.toBeFreedChunks 1
2025-06-22 20:44:56.689403+02:00 database: FileStore : serializeAndStore() c.id=8656 lastChunkId=8656
2025-06-22 20:44:56.689403+02:00 database: FileStore: storeBuffer() c.id=8656
2025-06-22 20:44:56.697399+02:00 user: FileStore : dropUnusedChunks.toBeFreedChunks 6
2025-06-22 20:44:56.698401+02:00 user: RAS : compactMoveChunks
2025-06-22 20:44:56.698401+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.698401+02:00 database: RAS header: H:2,block:8be,blockSize:1000,chunk:21d0,created:19798f30e74,format:3,version:21d0,fletcher:c297f4f9

2025-06-22 20:44:56.707399+02:00 database: FileStore : serializeAndStore() c.id=8657 lastChunkId=8657
2025-06-22 20:44:56.707399+02:00 database: FileStore: storeBuffer() c.id=8657
2025-06-22 20:44:56.707399+02:00 database: RAS : writeChunk->writeStoreHeader()
2025-06-22 20:44:56.707399+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.707399+02:00 database: RAS header: H:2,block:459,blockSize:1000,chunk:21d1,created:19798f30e74,format:3,version:21d1,fletcher:3f3dc6cc

2025-06-22 20:44:56.707399+02:00 database: RAS : writeChunk->shrinkStoreIfPossible()
2025-06-22 20:44:56.717001+02:00 database: FileStore : serializeAndStore() c.id=8658 lastChunkId=8658
2025-06-22 20:44:56.717001+02:00 database: FileStore: storeBuffer() c.id=8658
2025-06-22 20:44:56.717001+02:00 database: RAS : writeChunk->writeStoreHeader()
2025-06-22 20:44:56.717001+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.717001+02:00 database: RAS header: H:2,block:870,blockSize:1000,chunk:21d2,created:19798f30e74,format:3,version:21d2,fletcher:ab84c3ce

2025-06-22 20:44:56.717001+02:00 database: RAS : writeChunk->shrinkStoreIfPossible()
2025-06-22 20:44:56.717001+02:00 database: RAS : shrinkIfPossible->truncate() end=8851456 size=17711104
2025-06-22 20:44:56.720998+02:00 database: RAS : compactMoveChunks->shrinkIfPossible()
2025-06-22 20:44:56.725998+02:00 database: MVStore: Increase current version to 8659
2025-06-22 20:44:56.725998+02:00 database: MVStore: store->FileStore.dropUnusedChunks()
2025-06-22 20:44:56.726998+02:00 user: FileStore : dropUnusedChunks.toBeFreedChunks 2
2025-06-22 20:44:56.758192+02:00 database: FileStore : serializeAndStore() c.id=8659 lastChunkId=8659
2025-06-22 20:44:56.758192+02:00 database: FileStore: storeBuffer() c.id=8659
2025-06-22 20:44:56.760193+02:00 database: RAS : writeChunk->writeStoreHeader()
2025-06-22 20:44:56.760193+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.760193+02:00 database: RAS header: H:2,block:46,blockSize:1000,chunk:21d3,created:19798f30e74,format:3,version:21d3,fletcher:84bd124d

2025-06-22 20:44:56.760193+02:00 database: RAS : writeChunk->shrinkStoreIfPossible()
2025-06-22 20:44:56.763192+02:00 user: FileStore : dropUnusedChunks.toBeFreedChunks 2
2025-06-22 20:44:56.764193+02:00 user: RAS : compaction loop 2
2025-06-22 20:44:56.764193+02:00 database: RAS : writeCleanShutdownMark->shrinkStoreIfPossible()
2025-06-22 20:44:56.764193+02:00 database: RAS : shrinkIfPossible->truncate() end=4575232 size=8851456
2025-06-22 20:44:56.764193+02:00 database: RAS : writeStoreHeader()
2025-06-22 20:44:56.764193+02:00 database: RAS header: H:2,block:46,blockSize:1000,chunk:21d3,clean:1,created:19798f30e74,format:3,version:21d3,fletcher:6fed46b5

2025-06-22 20:44:56.765193+02:00 user: MVStore : Maps closed
2025-06-22 20:44:56.766193+02:00 database: closed
2025-06-22 20:44:56.766193+02:00 database: disconnected session #3
2025-06-22 20:44:56.769192+02:00 database: opening C:/Users/Arthur/.owlplug/owlplug (build 239)
2025-06-22 20:44:56.772192+02:00 database: MVStore  : setCurrentVersion 0
2025-06-22 20:44:56.773192+02:00 database: 2135232579 RAS : readStoreHeader()
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- created=19798f30e74
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- H=2
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- format=3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- chunk=21d3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- block=46
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- clean=1
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- version=21d3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- blockSize=1000
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- created=19798f30e74
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- H=2
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- format=3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- chunk=21d3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- block=46
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- clean=1
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- version=21d3
2025-06-22 20:44:56.773192+02:00 database: RAS : ---- blockSize=1000
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader() assumeCleanShutdown=true newest.id=8659 newest.version=8659
2025-06-22 20:44:56.773192+02:00 database: FileStore : setLastChunk() last.id=8659
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:d4a,block:2,len:d,pages:33,max:d590,map:2b9,next:29,root:35280002eda54,time:d0eb,version:d4a,toc:becc
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:1035,block:f,len:f,pages:3c,max:fc40,map:371,next:3c,root:40d4000367416,time:ea78,version:1035,toc:ddf7
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:1c0e,block:1e,len:1a,pages:70,max:1d3b0,map:753,next:6c,root:703800061ed16,time:1686c,version:1c0e,toc:18d05
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:21ce,block:38,len:9,pages:19,max:8fd0,map:e41,next:479,root:87380001c0ac3,time:22785,version:21ce,toc:7f13
2025-06-22 20:44:56.773192+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:21cf,block:41,len:5,pages:12,max:5590,map:e43,next:457,root:873c0000f5283,time:22829,version:21cf,toc:4cef
// ----------------------- Here chunks chunk:8656 (21cf) cannot  be retrieved from the file
// ----------------------- This causes the database to rollback from version 8656 to 7182
2025-06-22 20:44:56.774192+02:00 database: FileStore : readChunkHeaderOptionally() Exception:Reading from file sun.nio.ch.FileChannelImpl@1de83efb failed at 4575232 (length 4575232), read 0, remaining 1024 [2.3.239/1]
2025-06-22 20:44:56.779195+02:00 database: Header cannot be found block=1117,expectedId=8656
2025-06-22 20:44:56.779195+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = null
2025-06-22 20:44:56.779195+02:00 database: RAS : readStoreHeader() assumeCleanShutdown=false
2025-06-22 20:44:56.779195+02:00 database: FileStore : setLastChunk() last.id=8655
2025-06-22 20:44:56.779195+02:00 database: FileStore : setLastChunk() last.id=8654
2025-06-22 20:44:56.779195+02:00 database: FileStore : setLastChunk() last.id=7182
2025-06-22 20:44:56.779195+02:00 database: Header cannot be found block=30expectedId=7178
2025-06-22 20:44:56.779195+02:00 database: FileStore : readChunkHeaderOptionally() Exception:File corrupt reading chunk at position 135168 [2.3.239/6]
2025-06-22 20:44:56.779195+02:00 database: Header cannot be found block=33,expectedId=7179
2025-06-22 20:44:56.779195+02:00 database: Header cannot be found block=56,expectedId=7181
2025-06-22 20:44:56.779195+02:00 database: RAS : readStoreHeader() completed
2025-06-22 20:44:56.779195+02:00 database: FileStore : start() lastChunkVersion=7182
2025-06-22 20:44:56.779195+02:00 database: MVStore  : setCurrentVersion 7182
2025-06-22 20:44:56.782193+02:00 database: opened C:/Users/Arthur/.owlplug/owlplug
2025-06-22 20:44:56.782193+02:00 database: connecting session #3 to C:/Users/Arthur/.owlplug/owlplug

It appears the chunk 8656 is dropped upon compaction during map/database closure and (probably) flagged as FileStore : dropUnusedChunks.toBeFreedChunks. I noticed that the database startup recovery is starting with RAS : readStoreHeader() assumeCleanShutdown=false.

There are several possibilities:

  1. The chunk shouldn't be freed; the change is correctly reflected in metadata, and the startup recovery behaves correctly.
    Chunk is added to the deadChunk list by the acceptChunkOccupancyChanges call. This decision appears valid as the page was evicted from the map. This could be checked again as I'm not sure to understand the page eviction detection logic behind Chunk.accountForRemovedPage().

  2. The chunk should be freed; the change is not correctly reflected in metadata, and the startup recovery behaves correctly.
    This seems to be the most likely issue based on (2) and (3).

  3. The chunk should be freed; the change is correctly reflected in metadata, but the startup recovery mode is not working correctly.
    The startup recovery seems to behave well by falling back to the most recent chunks and validating the layout. This causes the database to roll back in time as the latest chunk will be considered as corrupted. Sometimes, multiple chunks cannot be recovered, and the database can be rolled back for hundreds of versions, sometimes leaving an empty table.

I've added more logs to check compaction loop execution and verify markMetaChanged is called upon chunk deletion, and how compactMoveChunk is executed.

/*SQL */COMMIT;
2025-07-09 22:48:04.506193+02:00 database: disconnecting session #3
2025-07-09 22:48:04.506193+02:00 database: closing D:/temp/owlplug/owlplug
2025-07-09 22:48:04.506193+02:00 database: MVStore: store() -> Increase current version to 6240
2025-07-09 22:48:04.506193+02:00 database: MVStore: store() -> FileStore.dropUnusedChunks()
2025-07-09 22:48:04.506193+02:00 database: FileStore : dropUnusedChunks.toBeFreedChunks 0
2025-07-09 22:48:04.506193+02:00 database: MVStore: store() -> FileStore.storeNow()
2025-07-09 22:48:04.507190+02:00 database: FileStore : StoreIt version=6240,syncWrite=true
2025-07-09 22:48:04.507190+02:00 database: FileStore : serializeAndStore() c.id=6240 lastChunkId=6240
2025-07-09 22:48:04.508191+02:00 database: FileStore: storeBuffer() c.id=6240
2025-07-09 22:48:04.508191+02:00 database: RAS : writeStoreHeader()
2025-07-09 22:48:04.508191+02:00 database: RAS header: H:2,block:9a3,blockSize:1000,chunk:1860,created:197f0cfd8aa,format:3,version:1860,fletcher:e773fd22

2025-07-09 22:48:04.508191+02:00 database: RAS : writeChunk->shrinkStoreIfPossible()
2025-07-09 22:48:04.508191+02:00 user: MVStore: Closing MVStore
2025-07-09 22:48:04.508191+02:00 user: MVStore : Stopping FileStore
2025-07-09 22:48:04.508191+02:00 database: RAS : compactStore()
2025-07-09 22:48:04.508191+02:00 database: FileStore : rewriteChunks()
2025-07-09 22:48:04.525190+02:00 database: RAS : compactStore() -> Starting compaction loop 1
2025-07-09 22:48:04.636190+02:00 database: RAS : compactMoveChunks() -> dropUnusedChunks()
2025-07-09 22:48:04.636190+02:00 database: FileStore : dropUnusedChunk -> mvStore.markMetaChanged() for chunkId=6233
// ----------------------- Here chunks 6238 is removed
2025-07-09 22:48:04.636190+02:00 database: FileStore : dropUnusedChunk -> mvStore.markMetaChanged() for chunkId=6238
2025-07-09 22:48:04.636190+02:00 database: FileStore : dropUnusedChunks.toBeFreedChunks 2
2025-07-09 22:48:04.636190+02:00 database: FileStore : dropUnusedChunks free chunk space for : 6233,6238
// ----------------------- Skipping the compactMoveChunks
2025-07-09 22:48:04.636190+02:00 database: RAS : compactMoveChunks() -> compactMoveChunks skipped getFillRate=94,targetFillRate=90
2025-07-09 22:48:04.636190+02:00 database: FileStore : rewriteChunks()
2025-07-09 22:48:04.638190+02:00 database: RAS : compaction loop completed 1
2025-07-09 22:48:04.638190+02:00 database: RAS : writeCleanShutdownMark->shrinkStoreIfPossible()
// ----------------------- Store is truncated
// ----------------------- Previous call to shrinkStoreIfPossible() did not trigger the truncate
// ----------------------- Probably removing the space left by evicted chunks 6233, 6238
2025-07-09 22:48:04.638190+02:00 database: RAS : shrinkIfPossible->truncate() end=14659584 size=14671872
2025-07-09 22:48:04.638190+02:00 database: RAS : writeStoreHeader()
2025-07-09 22:48:04.638190+02:00 database: RAS header: H:2,block:9a3,blockSize:1000,chunk:1860,clean:1,created:197f0cfd8aa,format:3,version:1860,fletcher:1b706557

2025-07-09 22:48:04.713191+02:00 user: MVStore : Maps closed
2025-07-09 22:48:04.714191+02:00 database: closed
2025-07-09 22:48:04.714191+02:00 database: disconnected session #3
2025-07-09 22:48:04.716191+02:00 database: opening D:/temp/owlplug/owlplug (build 239)
2025-07-09 22:48:04.718194+02:00 database: MVStore  : setCurrentVersion 0
2025-07-09 22:48:04.718194+02:00 database: 284535385 RAS : readStoreHeader()
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- created=197f0cfd8aa
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- H=2
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- format=3
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- chunk=1860
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- block=9a3
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- clean=1
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- version=1860
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- blockSize=1000
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- created=197f0cfd8aa
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- H=2
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- format=3
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- chunk=1860
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- block=9a3
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- clean=1
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- version=1860
2025-07-09 22:48:04.718194+02:00 database: RAS : ---- blockSize=1000
2025-07-09 22:48:04.718194+02:00 database: RAS : readStoreHeader() assumeCleanShutdown=true newest.id=6240 newest.version=6240
2025-07-09 22:48:04.718194+02:00 database: FileStore : setLastChunk() last.id=6240
2025-07-09 22:48:04.718194+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:17cc,block:2,len:465,pages:a7d,max:5556a0,map:fe5,next:a0b,root:5f300117c55d8,time:216c11,version:17cc,toc:45f86a
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:1859,block:467,len:da,pages:3fc,max:107340,map:104f,next:ded,root:61640035a749c,time:222d1b,version:1859,toc:d76c9
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:185b,block:9aa,len:451,pages:a85,max:53e820,map:1051,next:1240,root:616c011288d1a,time:222ea8,version:185b,toc:44ad88
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = chunk:185c,block:543,len:f,pages:23,max:11000,map:1051,next:552,root:617000034b9dc,time:222faa,version:185c,toc:e0c5
2025-07-09 22:48:04.719206+02:00 database: FileStore : readChunkHeaderOptionally() Exception:Reading from file sun.nio.ch.FileChannelImpl@30616993 failed at 14663680 (length 14659584), read 0, remaining 1024 [2.3.239/1]
// ----------------------- Here chunks chunk:6238(21cf) cannot  be retrieved from the file
// ----------------------- This causes the database to rollback from 6240 to 6236
2025-07-09 22:48:04.719206+02:00 database: Header cannot be found block=3580expectedId=6238
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader()->readChunkHeaderAndFooter() = null
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader() assumeCleanShutdown=false
2025-07-09 22:48:04.719206+02:00 database: FileStore : setLastChunk() last.id=6236
2025-07-09 22:48:04.719206+02:00 database: FileStore : readChunkHeaderOptionally() Exception:Reading from file sun.nio.ch.FileChannelImpl@30616993 failed at 19136512 (length 14659584), read 0, remaining 1024 [2.3.239/1]
2025-07-09 22:48:04.719206+02:00 database: Header cannot be found block=4672expectedId=6232
2025-07-09 22:48:04.719206+02:00 database: RAS : readStoreHeader() completed
2025-07-09 22:48:04.719206+02:00 database: FileStore : start() lastChunkVersion=6236
2025-07-09 22:48:04.719206+02:00 database: MVStore  : setCurrentVersion 6236
2025-07-09 22:48:04.722192+02:00 database: opened D:/temp/owlplug/owlplug
2025-07-09 22:48:04.722192+02:00 database: connecting session #3 to D:/temp/owlplug/owlplug

So here is my understanding of the problem. Within the compaction loop in RandomAccessStore.compactMoveChunk() there is a call to dropUnusedChunks(). This call is flagging chunks, which are removed from the layout, added to the deadChunks list, and freed on the freeSpace.

public void compactMoveChunks(int targetFillRate, long moveSize, MVStore mvStore) {
if (isSpaceReused()) {
mvStore.executeFilestoreOperation(() -> {
dropUnusedChunks();
saveChunkLock.lock();
try {
if (hasPersistentData() && getFillRate() <= targetFillRate) {
compactMoveChunks(moveSize);
}
} finally {
saveChunkLock.unlock();
}
});
}
}

Later in compactMoveChunks(), an overloaded method is called compactMoveChunks(moveSize), but only if the current store file rate is under the targetFillRate. If we want to persist the chunks deletion, this method is the "last chance" to call the store() to create a new version and a new Chunk. If this method is not called, the deleted chunk will remain in metadata and the file.

When the compaction loop completes, either because max compaction time is exceeded or the expected rate has been reached. The shrinkStoreIfPossible() method is called to complete the database closure in writeCleanShutdownMark() method. As the shrink logic is based on the freeSpace, the database file can be truncated, dropping the chunks flagged as deleted but still referenced in the last chunk layout on the file.

When the database is reopened, the last chunk is loaded, but the referenced (deleted) chunk cannot be retrieved as the chunk location is now outside the file boundaries. The recovery process and roll-back is starting, and some data disappears.

Possible solutions

  • To fix the bug, I forced the execution of compactMoveChunks if chunks are dropped. Usually, issues always appear after ~1-2 minutes of batch insertions in my app. With this change, no issues occurs after 1h.
    Force chunk space reallocation if chunks are dropped DropSnorz/h2database#2

  • Maybe rework the shrink/free space logic or prevent some chunks from joining the deadChunks list too early.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions