/* * Copyright (c) 2009, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist, * Felix Hupfeld, Felix Langner, Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ package de.mxro.thrd.babudb05.conversion; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.Map.Entry; import de.mxro.thrd.babudb05.config.BabuDBConfig; public class DBWriter { public static final String SNAPSHOT_DIR_NAME = "snapshots"; /** * Checks if a certain data version is supported by the writer. * * @param ver * the version to be checked * * @return <code>true</code>, if it is supported, <code>false</code>, * otherwise */ public static boolean checkVersionSupport(int ver) { return BabuDBVersionReader.checkVersionSupport(ver); } /** * <p> * This method creates version independent representations of all indices * located in the database directory specified in the given configuration. * The representations is written to separate files, where each file is * named like the number of the index it belongs to. * * <p> * The files are located in subdirectories of the given target directory, * where each subdirectory is named like the database it belongs to. * </p> * * <p> * Snapshots are represented alike, as subdirectories with the name of the * snapshot located in a subdirectory of the database directory with the * name specified in <code>SNAPSHOT_DIR_NAME</code>. * </p> * * <p> * An example of the content of a temporary directory called '/tmp': * * <pre> * /tmp/db1/1 * /tmp/db2/1 * /tmp/db2/2 * /tmp/db2/3 * /tmp/db2/snapshots/snap1/1 * /tmp/db2/snapshots/snap1/2 * </pre> * * </p> * * <p> * For the version independent representation of an index, we chose a stream * of the following format: * * <pre> * keylength: 4 bytes | key: keylenth bytes | valuelength: 4 bytes | value: valuelength bytes ... * </pre> * * </p> * * @param cfg * configuration parameters containing information like index and * log file locations and encoding parameters * @param ver * the data version from which the database needs to be converted * @param targetDir * the target directory to which the version independent * representation is written * @exception IOException * if an I/O error occurs while writing the version * independent representation */ public static void writeDB(BabuDBConfig cfg, int ver, String targetDir) throws IOException { BabuDBVersionReader reader = null; try { File trgDir = new File(targetDir); trgDir.mkdirs(); // create a reader for the given BabuDB version reader = new BabuDBVersionReader(ver, cfg.getProps()); // write all databases for (String dbName : reader.getAllDatabases()) { File dbDir = new File(trgDir, dbName); dbDir.mkdir(); // write all indices for (int i = 0; i < reader.getNumIndics(dbName); i++) writeIndexFile(dbName, null, i, new File(dbDir, i + ""), reader); // write all snapshots String[] snaps = reader.getAllSnapshots(dbName); if (snaps.length == 0) continue; for (String snapName : snaps) for (int i = 0; i < reader.getNumIndics(dbName); i++) writeIndexFile(dbName, snapName, i, new File(dbDir, i + ""), reader); } } finally { if (reader != null) reader.shutdown(); } } private static void writeIndexFile(String dbName, String snapName, int indexId, File targetFile, BabuDBVersionReader reader) throws IOException { OutputStream out = new FileOutputStream(targetFile); ByteBuffer lenBytes = ByteBuffer.wrap(new byte[4]); Iterator<Entry<byte[], byte[]>> it = snapName == null ? reader.getIndexContent(dbName, indexId) : reader.getIndexContent(dbName, snapName, indexId); while (it.hasNext()) { Entry<byte[], byte[]> next = it.next(); // write key length + key lenBytes.putInt(next.getKey().length); lenBytes.position(0); out.write(lenBytes.array()); out.write(next.getKey()); // write value length + value lenBytes.putInt(next.getValue().length); lenBytes.position(0); out.write(lenBytes.array()); out.write(next.getValue()); } out.close(); } }