diff --git a/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java b/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java index 1ed32abb9..b3b652c5e 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java @@ -32,6 +32,13 @@ public interface ChecksumEntry { * only when value bytes was updated directly, for example though flyweight implementation of * a value * interface. + * + * @throws UnsupportedOperationException if checksums are not stored in the containing Chronicle + * Hash + * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the + * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the + * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code updateChecksum()} + * method is enabled when at least update lock is held. */ void updateChecksum(); @@ -39,6 +46,12 @@ public interface ChecksumEntry { * Computes checksum from the entry bytes and checks whether it is equal to the stored checksum. * * @return {@code true} if stored checksum equals to checksum computed from the entry bytes + * @throws UnsupportedOperationException if checksums are not stored in the containing Chronicle + * Hash + * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the + * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the + * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code checkSum()} method is + * enabled when at least update lock is held. */ boolean checkSum(); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java index cc437d1d7..18cc8a0a3 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java @@ -164,6 +164,7 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry throw new UnsupportedOperationException( "Checksum is not stored in this Chronicle Hash"); } + s.innerUpdateLock.lock(); initDelayedUpdateChecksum(true); } @@ -174,6 +175,10 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry throw new UnsupportedOperationException( "Checksum is not stored in this Chronicle Hash"); } + // This is needed, because a concurrent update lock holder might perform an entry update, + // but not yet written a checksum (because checksum write is delayed to the update unlock). + // So checkSum() on read lock level might result to false negative results. + s.innerUpdateLock.lock(); return delayedUpdateChecksumInit() || checksumStrategy.innerCheckSum(); }