Fallback to old manifest if most recent is unparseable patch by Carl Yeksigian; reviewed by jbellis for CASSANDRA-5041
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9b61606a Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9b61606a Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9b61606a Branch: refs/heads/trunk Commit: 9b61606a5d450df15261cc2f04c006323ae2881e Parents: 8752bfa Author: Jonathan Ellis <jbel...@apache.org> Authored: Mon Dec 10 13:36:20 2012 -0600 Committer: Jonathan Ellis <jbel...@apache.org> Committed: Mon Dec 10 13:37:50 2012 -0600 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/db/compaction/LeveledManifest.java | 56 ++++++++++----- 2 files changed, 38 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/9b61606a/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index c7559a3..eb1c3a8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 1.2.1 + * Fall back to old manifest if most recent is unparseable (CASSANDRA-5041) * pool [Compressed]RandomAccessReader objects on the partitioned read path (CASSANDRA-4942) * Add debug logging to list filenames processed by Directories.migrateFile http://git-wip-us.apache.org/repos/asf/cassandra/blob/9b61606a/src/java/org/apache/cassandra/db/compaction/LeveledManifest.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/compaction/LeveledManifest.java b/src/java/org/apache/cassandra/db/compaction/LeveledManifest.java index a992d11..c1d831b 100644 --- a/src/java/org/apache/cassandra/db/compaction/LeveledManifest.java +++ b/src/java/org/apache/cassandra/db/compaction/LeveledManifest.java @@ -107,33 +107,51 @@ public class LeveledManifest if (manifestFile == null) return; - ObjectMapper m = new ObjectMapper(); try { - JsonNode rootNode = m.readValue(manifestFile, JsonNode.class); - JsonNode generations = rootNode.get("generations"); - assert generations.isArray(); - for (JsonNode generation : generations) + parseManifest(manifest, sstables, manifestFile); + } + catch (Exception e) + { + logger.debug("Error parsing manifest", e); + File oldFile = new File(manifestFile.getPath().replace(EXTENSION, "-old.json")); + if (oldFile.exists()) { - int level = generation.get("generation").getIntValue(); - JsonNode generationValues = generation.get("members"); - for (JsonNode generationValue : generationValues) + try { - for (SSTableReader ssTableReader : sstables) - { - if (ssTableReader.descriptor.generation == generationValue.getIntValue()) - { - logger.debug("Loading {} at L{}", ssTableReader, level); - manifest.add(ssTableReader, level); - } - } + parseManifest(manifest, sstables, oldFile); + return; + } + catch (Exception old) + { + logger.debug("Old manifest present but corrupt", old); } } + logger.warn("Manifest present but corrupt. Cassandra will re-level {} from scratch", cfs.columnFamily); } - catch (Exception e) + } + + private static void parseManifest(LeveledManifest manifest, Iterable<SSTableReader> sstables, File manifestFile) throws IOException + { + ObjectMapper m = new ObjectMapper(); + JsonNode rootNode = m.readValue(manifestFile, JsonNode.class); + JsonNode generations = rootNode.get("generations"); + assert generations.isArray(); + for (JsonNode generation : generations) { - // TODO try to recover -old first - logger.error("Manifest present but corrupt. Cassandra will compact levels from scratch", e); + int level = generation.get("generation").getIntValue(); + JsonNode generationValues = generation.get("members"); + for (JsonNode generationValue : generationValues) + { + for (SSTableReader ssTableReader : sstables) + { + if (ssTableReader.descriptor.generation == generationValue.getIntValue()) + { + logger.debug("Loading {} at L{}", ssTableReader, level); + manifest.add(ssTableReader, level); + } + } + } } }