Skip to content

Commit d7e7059

Browse files
committed
Add revert-metadata subcommand
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
1 parent 5199229 commit d7e7059

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright Hyperledger Besu Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.cli.subcommands.storage;
16+
17+
import org.hyperledger.besu.cli.util.VersionProvider;
18+
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
19+
20+
import java.io.File;
21+
import java.io.IOException;
22+
import java.nio.file.Path;
23+
import java.util.OptionalInt;
24+
25+
import com.fasterxml.jackson.databind.ObjectMapper;
26+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
27+
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
30+
import picocli.CommandLine;
31+
import picocli.CommandLine.Command;
32+
import picocli.CommandLine.ParentCommand;
33+
34+
/** The revert metadata to v1 subcommand. */
35+
@Command(
36+
name = "revert-metadata",
37+
description = "Revert database metadata to previous format",
38+
mixinStandardHelpOptions = true,
39+
versionProvider = VersionProvider.class,
40+
subcommands = RevertMetadataSubCommand.v2ToV1.class)
41+
public class RevertMetadataSubCommand implements Runnable {
42+
private static final Logger LOG = LoggerFactory.getLogger(RevertMetadataSubCommand.class);
43+
private static final String METADATA_FILENAME = "DATABASE_METADATA.json";
44+
private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new Jdk8Module());
45+
46+
@SuppressWarnings("unused")
47+
@ParentCommand
48+
private StorageSubCommand parentCommand;
49+
50+
@SuppressWarnings("unused")
51+
@CommandLine.Spec
52+
private CommandLine.Model.CommandSpec spec;
53+
54+
@Override
55+
public void run() {
56+
spec.commandLine().usage(System.out);
57+
}
58+
59+
@Command(
60+
name = "v2-to-v1",
61+
description = "Revert a database metadata v2 format to v1 format",
62+
mixinStandardHelpOptions = true,
63+
versionProvider = VersionProvider.class)
64+
static class v2ToV1 implements Runnable {
65+
66+
@SuppressWarnings("unused")
67+
@CommandLine.Spec
68+
private CommandLine.Model.CommandSpec spec;
69+
70+
@SuppressWarnings("unused")
71+
@ParentCommand
72+
private RevertMetadataSubCommand parentCommand;
73+
74+
@Override
75+
public void run() {
76+
77+
final Path dataDir = parentCommand.parentCommand.parentCommand.dataDir();
78+
79+
final File dbMetadata = dataDir.resolve(METADATA_FILENAME).toFile();
80+
if (!dbMetadata.exists()) {
81+
String errMsg =
82+
String.format(
83+
"Could not find database metadata file %s, check your data dir %s",
84+
dbMetadata, dataDir);
85+
LOG.error(errMsg);
86+
throw new IllegalArgumentException(errMsg);
87+
}
88+
try {
89+
final var root = MAPPER.readTree(dbMetadata);
90+
if (!root.has("v2")) {
91+
String errMsg =
92+
String.format("Database metadata file %s is not in v2 format", dbMetadata);
93+
LOG.error(errMsg);
94+
throw new IllegalArgumentException(errMsg);
95+
}
96+
97+
final var v2Obj = root.get("v2");
98+
if (!v2Obj.has("format")) {
99+
String errMsg =
100+
String.format(
101+
"Database metadata file %s is malformed, \"format\" field not found", dbMetadata);
102+
LOG.error(errMsg);
103+
throw new IllegalArgumentException(errMsg);
104+
}
105+
106+
final var formatField = v2Obj.get("format").asText();
107+
final OptionalInt maybePrivacyVersion =
108+
v2Obj.has("privacyVersion")
109+
? OptionalInt.of(v2Obj.get("privacyVersion").asInt())
110+
: OptionalInt.empty();
111+
112+
final DataStorageFormat dataStorageFormat = DataStorageFormat.valueOf(formatField);
113+
final int v1Version =
114+
switch (dataStorageFormat) {
115+
case FOREST -> 1;
116+
case BONSAI -> 2;
117+
};
118+
119+
@JsonSerialize
120+
record V1(int version, OptionalInt privacyVersion) {}
121+
122+
MAPPER.writeValue(dbMetadata, new V1(v1Version, maybePrivacyVersion));
123+
LOG.info("Successfully reverted database metadata from v2 to v1 in {}", dbMetadata);
124+
} catch (IOException ioe) {
125+
new RuntimeException(ioe);
126+
}
127+
}
128+
}
129+
}

besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
subcommands = {
4949
StorageSubCommand.RevertVariablesStorage.class,
5050
RocksDbSubCommand.class,
51-
TrieLogSubCommand.class
51+
TrieLogSubCommand.class,
52+
RevertMetadataSubCommand.class
5253
})
5354
public class StorageSubCommand implements Runnable {
5455

0 commit comments

Comments
 (0)