/* * Copyright (c) 2009 - 2011, 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.lsmdb; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.LinkedList; import java.util.List; import java.util.Set; import de.mxro.thrd.babudb05.api.dev.BabuDBInternal; import de.mxro.thrd.babudb05.api.dev.DatabaseInternal; import de.mxro.thrd.babudb05.api.dev.DatabaseManagerInternal; import de.mxro.thrd.babudb05.api.exception.BabuDBException; import de.mxro.thrd.babudb05.api.exception.BabuDBException.ErrorCode; import de.mxro.thrd.babudb05.api.index.ByteRangeComparator; import de.mxro.thrd.xstreemfs.foundation.logging.Logging; import static de.mxro.thrd.babudb05.BabuDBFactory.*; /** * <p> * Operations to manipulate the DB-config-file. * </p> * * @author flangner * @since 09/02/2009 */ public class DBConfig { private final BabuDBInternal dbs; private final File configFile; private boolean conversionRequired; private int dbFormatVer; public DBConfig(BabuDBInternal dbs) throws BabuDBException { this.dbs = dbs; this.configFile = new File(dbs.getConfig().getBaseDir() + dbs.getConfig().getDbCfgFile()); load(); } /** * Loads the configuration and each database from disk and replaces the data * of the existing DBs, while removing outdated one's. * * @throws BabuDBException */ public void reset() throws BabuDBException { DatabaseManagerInternal dbman = dbs.getDatabaseManager(); assert (dbman != null) : "The DatabaseManager is not available!"; ObjectInputStream ois = null; try { List<Integer> ids = new LinkedList<Integer>(); if (configFile.exists()) { ois = new ObjectInputStream(new FileInputStream(configFile)); final int dbFormatVer = ois.readInt(); if (dbFormatVer != BABUDB_DB_FORMAT_VERSION) { throw new BabuDBException(ErrorCode.IO_ERROR, "on-disk format (version " + dbFormatVer + ") is incompatible with this BabuDB release " + "(uses on-disk format version " + BABUDB_DB_FORMAT_VERSION + ")"); } final int numDB = ois.readInt(); dbman.setNextDBId(ois.readInt()); for (int i = 0; i < numDB; i++) { Logging.logMessage(Logging.LEVEL_DEBUG, this, "loading DB..."); final String dbName = (String) ois.readObject(); final int dbId = ois.readInt(); final int numIndex = ois.readInt(); ByteRangeComparator[] comps = new ByteRangeComparator[numIndex]; for (int idx = 0; idx < numIndex; idx++) { final String className = (String) ois.readObject(); ByteRangeComparator comp = dbman.getComparatorInstances().get(className); if (comp == null) { Class<?> clazz = Class.forName(className); comp = (ByteRangeComparator) clazz.newInstance(); dbman.getComparatorInstances().put(className, comp); } assert (comp != null); comps[idx] = comp; } ids.add(dbId); DatabaseInternal db; try { // reset existing DBs db = dbman.getDatabase(dbId); db.setLSMDB(new LSMDatabase(dbName, dbId, dbs.getConfig().getBaseDir() + dbName + File.separatorChar, numIndex, true, comps, dbs.getConfig().getCompression(), dbs.getConfig().getMaxNumRecordsPerBlock(), dbs.getConfig().getMaxBlockFileSize(), dbs.getConfig().getDisableMMap(), dbs.getConfig().getMMapLimit())); } catch (BabuDBException e) { db = new DatabaseImpl(dbs, new LSMDatabase(dbName, dbId, dbs.getConfig().getBaseDir() + dbName + File.separatorChar, numIndex, true, comps, dbs.getConfig().getCompression(), dbs.getConfig().getMaxNumRecordsPerBlock(), dbs.getConfig().getMaxBlockFileSize(), dbs.getConfig().getDisableMMap(), dbs.getConfig().getMMapLimit())); dbman.putDatabase(db); } Logging.logMessage(Logging.LEVEL_INFO, this, "loaded DB %s" + " successfully. [LSN %s]", dbName, db.getLSMDB().getOndiskLSN()); } } // delete remaining outdated DBs Set<Integer> outdatedIds = dbman.getAllDatabaseIds(); outdatedIds.removeAll(ids); if (outdatedIds.size() > 0) { for (int id : outdatedIds) { dbman.removeDatabaseById(id); } } } catch (InstantiationException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot instantiate comparator", ex); } catch (IllegalAccessException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot instantiate comparator", ex); } catch (IOException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, check path and access rights", ex); } catch (ClassNotFoundException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, config file might be corrupted", ex); } catch (ClassCastException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, config file might be corrupted", ex); } finally { if (ois != null) try { ois.close(); } catch (IOException e) { /* I don't care */ } } } /** * Loads the configuration and each database from disk. * * @throws BabuDBException */ public void load() throws BabuDBException { DatabaseManagerInternal dbman = dbs.getDatabaseManager(); assert (dbman != null) : "The DatabaseManager is not available!"; ObjectInputStream ois = null; try { if (configFile.exists()) { ois = new ObjectInputStream(new FileInputStream(configFile)); dbFormatVer = ois.readInt(); if (dbFormatVer != BABUDB_DB_FORMAT_VERSION) conversionRequired = true; final int numDB = ois.readInt(); dbman.setNextDBId(ois.readInt()); for (int i = 0; i < numDB; i++) { Logging.logMessage(Logging.LEVEL_DEBUG, this, "loading DB..."); final String dbName = (String) ois.readObject(); final int dbId = ois.readInt(); final int numIndex = ois.readInt(); ByteRangeComparator[] comps = new ByteRangeComparator[numIndex]; for (int idx = 0; idx < numIndex; idx++) { final String className = (String) ois.readObject(); ByteRangeComparator comp = dbman.getComparatorInstances().get(className); if (comp == null) { Class<?> clazz = Class.forName(className); comp = (ByteRangeComparator) clazz.newInstance(); dbman.getComparatorInstances().put(className, comp); } assert (comp != null); comps[idx] = comp; } if (!conversionRequired) { DatabaseInternal db = new DatabaseImpl(this.dbs, new LSMDatabase(dbName, dbId, this.dbs.getConfig().getBaseDir() + dbName + File.separatorChar, numIndex, true, comps, dbs.getConfig() .getCompression(), this.dbs.getConfig().getMaxNumRecordsPerBlock(), dbs.getConfig().getMaxBlockFileSize(), dbs.getConfig().getDisableMMap(), dbs.getConfig().getMMapLimit())); dbman.putDatabase(db); Logging.logMessage(Logging.LEVEL_DEBUG, this, "loaded DB " + dbName + "(" + dbId + ") successfully."); } } } } catch (InstantiationException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot instantiate comparator", ex); } catch (IllegalAccessException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot instantiate comparator", ex); } catch (IOException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, check path and access rights", ex); } catch (ClassNotFoundException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, config file might be corrupted", ex); } catch (ClassCastException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "cannot load database config, config file might be corrupted", ex); } finally { if (ois != null) try { ois.close(); } catch (IOException e) { /* who cares? */ } } } /** * saves the current database config to disk * * @param filename * path to the config file location * @throws BabuDBException */ public void save(String filename) throws BabuDBException { DatabaseManagerInternal dbman = dbs.getDatabaseManager(); synchronized (dbman.getDBModificationLock()) { try { File tempFile = new File(filename + ".in_progress"); FileOutputStream fos = new FileOutputStream(tempFile); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeInt(BABUDB_DB_FORMAT_VERSION); oos.writeInt(dbman.getAllDatabaseIds().size()); oos.writeInt(dbman.getNextDBId()); for (int dbId : dbman.getAllDatabaseIds()) { LSMDatabase db = dbman.getDatabase(dbId).getLSMDB(); oos.writeObject(db.getDatabaseName()); oos.writeInt(dbId); oos.writeInt(db.getIndexCount()); String[] compClasses = db.getComparatorClassNames(); for (int i = 0; i < db.getIndexCount(); i++) { oos.writeObject(compClasses[i]); } } oos.flush(); fos.flush(); fos.getFD().sync(); oos.close(); File dbFile = new File(filename); // try to rename the file boolean success = tempFile.renameTo(dbFile); if (!success) { // on Windows machines, the target mustn't exist; thus, it // is necessary to sacrifice atomicity and delete the // previous file before dbFile.delete(); tempFile.renameTo(dbFile); } } catch (IOException ex) { throw new BabuDBException(ErrorCode.IO_ERROR, "unable to save database configuration", ex); } } } public void save() throws BabuDBException { save(dbs.getConfig().getBaseDir() + dbs.getConfig().getDbCfgFile()); } public boolean isConversionRequired() { return conversionRequired; } public int getDBFormatVersion() { return dbFormatVer; } }