1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2010 Oracle. All rights reserved.
*
* $Id: MakeLogEntryVersionData.java,v 1.19.2.4 2010/01/04 15:30:44 cwl Exp $
*/
package com.sleepycat.je.logversion;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Set;
import javax.transaction.xa.XAResource;
import com.sleepycat.je.CheckpointConfig;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.JEVersion;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.XAEnvironment;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.log.TestUtilLogReader;
import com.sleepycat.je.log.LogUtils.XidImpl;
import com.sleepycat.je.util.TestUtils;
/**
* This standalone command line program generates log files named je-x.y.z.jdb
* and je-x.y.z.txt, where x.y.z is the version of JE used to run the program.
* This program needs to be run for the current version of JE when we release
* a new major version of JE. It does not need to be run again for older
* versions of JE, unless it is changed to generate new types of log entries
* and we need to verify those log entries for all versions of JE. In that
* the LogEntryVersionTest may also need to be changed.
*
* <p>Run this program with the desired version of JE in the classpath and pass
* a home directory as the single command line argument. After running this
* program move the je-x.y.z.* files to the directory of this source package.
* When adding je-x.y.z.jdb to CVS make sure to use -kb since it is a binary
* file.</p>
*
* <p>This program can be run using the logversiondata ant target.</p>
*
* @see LogEntryVersionTest
*/
public class MakeLogEntryVersionData {
/* Minimum child entries per BIN. */
private static int N_ENTRIES = 4;
private MakeLogEntryVersionData() {
}
public static void main(String[] args)
throws Exception {
if (args.length != 1) {
throw new Exception("Home directory arg is required.");
}
File homeDir = new File(args[0]);
File logFile = new File(homeDir, TestUtils.LOG_FILE_NAME);
File renamedLogFile = new File(homeDir, "je-" +
JEVersion.CURRENT_VERSION.getNumericVersionString() + ".jdb");
File summaryFile = new File(homeDir, "je-" +
JEVersion.CURRENT_VERSION.getNumericVersionString() + ".txt");
if (logFile.exists()) {
throw new Exception("Home directory must be empty of log files.");
}
EnvironmentConfig envConfig = TestUtils.initEnvConfig();
DbInternal.disableParameterValidation(envConfig);
envConfig.setAllowCreate(true);
envConfig.setTransactional(true);
/* Make as small a log as possible to save space in CVS. */
envConfig.setConfigParam
(EnvironmentParams.ENV_RUN_INCOMPRESSOR.getName(), "false");
envConfig.setConfigParam
(EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
envConfig.setConfigParam
(EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
envConfig.setConfigParam
(EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
/* force trace messages at recovery. */
envConfig.setConfigParam
(EnvironmentParams.JE_LOGGING_LEVEL.getName(), "CONFIG");
/* Use a 100 MB log file size to ensure only one file is written. */
envConfig.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
Integer.toString(100 * (1 << 20)));
/* Force BINDelta. */
envConfig.setConfigParam
(EnvironmentParams.BIN_DELTA_PERCENT.getName(),
Integer.toString(75));
/* Force INDelete -- only used when the root is purged. */
envConfig.setConfigParam
(EnvironmentParams.COMPRESSOR_PURGE_ROOT.getName(), "true");
/* Ensure that we create two BINs with N_ENTRIES LNs. */
envConfig.setConfigParam
(EnvironmentParams.NODE_MAX.getName(),
Integer.toString(N_ENTRIES));
CheckpointConfig forceCheckpoint = new CheckpointConfig();
forceCheckpoint.setForce(true);
XAEnvironment env = new XAEnvironment(homeDir, envConfig);
/*
* Make two shadow database. Database 1 is transactional and has
* aborts, database 2 is not transactional.
*/
for (int i = 0; i < 2; i += 1) {
boolean transactional = (i == 0);
String dbName = transactional ? Utils.DB1_NAME : Utils.DB2_NAME;
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
dbConfig.setTransactional(transactional);
dbConfig.setSortedDuplicates(true);
Database db = env.openDatabase(null, dbName, dbConfig);
Transaction txn = null;
if (transactional) {
txn = env.beginTransaction(null, null);
}
for (int j = 0; j < N_ENTRIES; j += 1) {
db.put(txn, Utils.entry(j), Utils.entry(0));
}
db.put(txn, Utils.entry(0), Utils.entry(1));
/* Must checkpoint to generate BINDeltas. */
env.checkpoint(forceCheckpoint);
/* Delete everything but the last LN to cause IN deletion. */
for (int j = 0; j < N_ENTRIES - 1; j += 1) {
db.delete(txn, Utils.entry(j));
}
if (transactional) {
txn.abort();
}
db.close();
}
/* Compress twice to delete DBIN, DIN, BIN, IN. */
env.compress();
env.compress();
/* DB2 was not aborted and will contain: {3, 0} */
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(false);
dbConfig.setReadOnly(true);
dbConfig.setSortedDuplicates(true);
Database db = env.openDatabase(null, Utils.DB2_NAME, dbConfig);
Cursor cursor = db.openCursor(null, null);
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry data = new DatabaseEntry();
OperationStatus status = cursor.getFirst(key, data, null);
if (status != OperationStatus.SUCCESS) {
throw new Exception("Expected SUCCESS but got: " + status);
}
if (Utils.value(key) != 3 || Utils.value(data) != 0) {
throw new Exception("Expected {3,0} but got: {" +
Utils.value(key) + ',' +
Utils.value(data) + '}');
}
} finally {
cursor.close();
}
db.close();
/*
* Make database 3, which is transactional and has some explicit
* transaction commit record.
*/
dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
dbConfig.setTransactional(true);
Transaction txn = env.beginTransaction(null, null);
db = env.openDatabase(null, Utils.DB3_NAME, dbConfig);
OperationStatus status = db.put(txn, Utils.entry(99), Utils.entry(79));
assert status == OperationStatus.SUCCESS: "status=" + status;
db.close();
txn.commit();
/*
* Generate an XA txn Prepare. The transaction must be non-empty in
* order to actually log the Prepare.
*/
XidImpl xid =
new XidImpl(1, "MakeLogEntryVersionData".getBytes(), null);
env.start(xid, XAResource.TMNOFLAGS);
/* Re-write the existing {3,0} record. */
dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(false);
dbConfig.setReadOnly(false);
dbConfig.setTransactional(true);
dbConfig.setSortedDuplicates(true);
db = env.openDatabase(null, Utils.DB2_NAME, dbConfig);
db.put(null, Utils.entry(3), Utils.entry(0));
db.close();
env.prepare(xid);
env.rollback(xid);
env.close();
/*
* Get the set of all log entry types we expect to output. We exclude
* two types:
* - MapLN_TX, because MapLN (non-transactional) is now used instead.
* - INDelete, because root compression is no longer used.
*/
Set<LogEntryType> expectedTypes = LogEntryType.getAllTypes();
expectedTypes.remove(LogEntryType.LOG_MAPLN_TRANSACTIONAL);
expectedTypes.remove(LogEntryType.LOG_IN_DELETE_INFO);
/* Open read-only and write all LogEntryType names to a text file. */
envConfig.setReadOnly(true);
Environment env2 = new Environment(homeDir, envConfig);
PrintWriter writer = new PrintWriter
(new BufferedOutputStream(new FileOutputStream(summaryFile)));
TestUtilLogReader reader = new TestUtilLogReader
(DbInternal.envGetEnvironmentImpl(env2), true /* readFullItem */);
while (reader.readNextEntry()) {
LogEntryType type = reader.getEntryType();
writer.println(type.toStringNoVersion() + '/' +
reader.getEntryVersion());
expectedTypes.remove(type);
}
writer.close();
env2.close();
if (expectedTypes.size() > 0) {
throw new Exception("Types not output: " + expectedTypes);
}
if (!logFile.exists()) {
throw new Exception("What happened to: " + logFile);
}
if (!logFile.renameTo(renamedLogFile)) {
throw new Exception
("Could not rename: " + logFile + " to " + renamedLogFile);
}
System.out.println("Created: " + renamedLogFile);
System.out.println("Created: " + summaryFile);
}
}
|