Flush persistent H2 cache if the existing entries are incompatible

Some caches (e.g. 'diff_intraline') are peristent so that the entries
survive a Gerrit restart (e.g. because the entries are expensive to
compute). To persist the cache entries Java serialization is used. If
now a class for a cache entry is changed and its serialVersionUID is
updated, already peristent cache entries cannot be deserialized anymore
since their class is incompatible with the new cache entry class.

Flush the cache if incompatible cache entries are detected.

E.g. commit 2424a8a9d5 changed a cache
entry class and as result the existing entries of the 'diff_intraline'
cache could not be loaded anymore, which caused an exception on each
Gerrit startup and when trying to access one of these cached entries.
To get rid of these exeptions the Gerrit administrator had to manually
flush the cache.

Change-Id: Ia158855d983d51335ae2a4df2b73d6c14fc612f0
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin
2012-10-16 16:32:49 +02:00
parent f77e9a9109
commit 3f461de64e

View File

@@ -13,10 +13,12 @@ import com.google.common.hash.Funnels;
import com.google.common.hash.PrimitiveSink;
import com.google.inject.TypeLiteral;
import org.h2.jdbc.JdbcSQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.Connection;
@@ -390,6 +392,15 @@ public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> {
while (r.next()) {
b.put(keyType.get(r, 1));
}
} catch (JdbcSQLException e) {
if (e.getCause() instanceof InvalidClassException) {
log.warn("Entries cached for " + url
+ " have an incompatible class and can't be deserialized. "
+ "Cache is flushed.");
invalidateAll();
} else {
throw e;
}
} finally {
r.close();
}