/* * Copyright 2009-2016 Tilmann Zaeschke. All rights reserved. * * This file is part of ZooDB. * * ZooDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZooDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZooDB. If not, see <http://www.gnu.org/licenses/>. * * See the README and COPYING files for further information. */ package org.zoodb.tools.impl; import java.io.File; import java.io.IOException; import java.util.Properties; import javax.jdo.JDOException; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import org.zoodb.api.DBArrayList; import org.zoodb.api.DBHashMap; import org.zoodb.internal.server.DiskIO; import org.zoodb.internal.server.DiskIO.PAGE_TYPE; import org.zoodb.internal.server.SessionFactory; import org.zoodb.internal.server.StorageChannel; import org.zoodb.internal.server.StorageChannelOutput; import org.zoodb.internal.server.StorageRootFile; import org.zoodb.internal.server.index.FreeSpaceManager; import org.zoodb.internal.server.index.PagedOidIndex; import org.zoodb.internal.util.DBLogger; import org.zoodb.jdo.ZooJdoHelper; import org.zoodb.jdo.ZooJdoProperties; import org.zoodb.jdo.spi.PersistenceCapableImpl; import org.zoodb.schema.ZooSchema; import org.zoodb.tools.ZooConfig; public class DataStoreManagerOneFile implements DataStoreManager { private static final String DEFAULT_FOLDER = System.getProperty("user.home") + File.separator + "zoodb"; private String toPath(String dbName) { if (dbName.contains("\\") || dbName.contains("/") || dbName.contains(File.separator)) { return dbName; } return DEFAULT_FOLDER + File.separator + dbName; } /** * Create database files. * This requires an existing database folder. * @param dbName */ @Override public void createDb(String dbName) { String dbPath = toPath(dbName); DBLogger.debugPrint(1, "Creating DB file: " + dbPath); String folderPath = dbPath.substring(0, dbPath.lastIndexOf(File.separator)); File dbDir = new File(folderPath); if (!dbDir.exists()) { createDbFolder(dbDir); DBLogger.debugPrint(1, "Creating DB folder: " + dbDir.getAbsolutePath()); } //create files StorageChannel file = null; try { //DB file File dbFile = new File(toPath(dbName)); if (dbFile.exists()) { throw DBLogger.newUser("ZOO: DB already exists: " + dbFile); } if (!dbFile.createNewFile()) { throw DBLogger.newUser("ZOO: Error creating DB file: " + dbFile); } FreeSpaceManager fsm = new FreeSpaceManager(); file = new StorageRootFile(dbPath, "rw", ZooConfig.getFilePageSize(), fsm); StorageChannelOutput out = file.getWriter(false); fsm.initBackingIndexNew(file); int headerPage = out.allocateAndSeek(PAGE_TYPE.DB_HEADER, 0); if (headerPage != 0) { throw DBLogger.newFatalInternal("Header page = " + headerPage); } int rootPage1 = out.allocateAndSeek(PAGE_TYPE.ROOT_PAGE, 0); int rootPage2 = out.allocateAndSeek(PAGE_TYPE.ROOT_PAGE, 0); //header: this is written further down //write User data int userData = out.allocateAndSeek(PAGE_TYPE.USERS, 0); //dir for schemata int schemaData = out.allocateAndSeekAP(PAGE_TYPE.SCHEMA_INDEX, 0, -1); //ID of next page out.writeInt(0); //Schema ID / schema data (page or actual data?) //0 for no more schemata out.writeInt(0); //dir for indices int indexDirPage = out.allocateAndSeek(PAGE_TYPE.INDEX_CATALOG, 0); //ID of next page out.writeInt(0); //Schema ID / attribute ID / index type / Page ID //0 for nor more indices out.writeInt(0); //OID index PagedOidIndex oidIndex = new PagedOidIndex(file); // bootstrapSchema(raf, oidIndex); int oidPage = oidIndex.write(); //Free space index int freeSpacePg = fsm.write(); //write header out.seekPageForWrite(PAGE_TYPE.DB_HEADER, headerPage); out.writeInt(DiskIO.DB_FILE_TYPE_ID); out.writeInt(DiskIO.DB_FILE_VERSION_MAJ); out.writeInt(DiskIO.DB_FILE_VERSION_MIN); out.writeInt(ZooConfig.getFilePageSize()); out.writeInt(rootPage1); out.writeInt(rootPage2); writeRoot(out, rootPage1, 1, userData, oidPage, schemaData, indexDirPage, freeSpacePg, fsm.getPageCount()); writeRoot(out, rootPage2, 0, userData, oidPage, schemaData, indexDirPage, freeSpacePg, fsm.getPageCount()); file.close(); file = null; out = null; //initial schemata Properties props = new ZooJdoProperties(dbName); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm = pmf.getPersistenceManager(); pm.currentTransaction().begin(); ZooSchema schema = ZooJdoHelper.schema(pm); schema.addClass(PersistenceCapableImpl.class); schema.addClass(DBHashMap.class); schema.addClass(DBArrayList.class); pm.currentTransaction().commit(); pm.close(); pmf.close(); } catch (IOException e) { e.printStackTrace(); throw DBLogger.newUser("ERROR While creating database: " + dbPath, e); } finally { if (file != null) { try { file.close(); } catch (JDOException e) { e.printStackTrace(); //ignore } } } } // private void bootstrapSchema(PageAccessFile raf, PagedOidIndex oidIndex) { // PagedObjectAccess poa = new PagedObjectAccess(raf, oidIndex, null); // DataSerializer ds = new DataSerializer(poa, null, null); // ZooClassDef zpc = ZooClassDef.bootstrapZooPCImpl(); // ZooClassDef cd = ZooClassDef.bootstrapZooClassDef(); // cd.associateFields(); // cd.associateJavaTypes(); // PCContext pcc = new PCContext(cd, null, null); // zpc.jdoZooInit(ObjectState.PERSISTENT_NEW, pcc, zpc.getOid()); // cd.jdoZooInit(ObjectState.PERSISTENT_NEW, pcc, cd.getOid()); // ds.writeObject(zpc, cd, zpc.getOid()); // ds.writeObject(cd, cd, cd.getOid()); // } private void writeRoot(StorageChannelOutput out, int pageID, int txID, int userPage, int oidPage, int schemaPage, int indexPage, int freeSpaceIndexPage, int pageCount) { out.seekPageForWrite(PAGE_TYPE.ROOT_PAGE, pageID); //txID out.writeLong(txID); //User table out.writeInt(userPage); //OID table out.writeInt(oidPage); //schemata out.writeInt(schemaPage); //indices out.writeInt(indexPage); //free space index out.writeInt(freeSpaceIndexPage); //page count out.writeInt(pageCount); //last used oid out.writeLong(100); //txID out.writeLong(txID); } @Override public boolean removeDb(String dbName) { File dbFile = new File(toPath(dbName)); DBLogger.debugPrint(1, "Removing DB file: " + dbFile.getAbsolutePath()); if (!dbFile.exists()) { return false; //throw DBLogger.newUser("ZOO: DB folder does not exist: " + dbFile); } // if (!dbFile.delete()) { // throw DBLogger.newUser("ZOO: Could not remove DB file: " + dbFile); // } SessionFactory.cleanUp(dbFile); return dbFile.delete(); } /** * Create a repository (directory/folder) to contain databases. */ private void createDbFolder(File dbDir) { if (dbDir.exists()) { return; //throw new JDOUserException("ZOO: Repository exists: " + dbFolder); } boolean r = dbDir.mkdirs(); if (!r) { throw DBLogger.newUser("Could not create folders: " + dbDir.getAbsolutePath()); } } @Override public String getDefaultDbFolder() { return DEFAULT_FOLDER; } @Override public String getDbPath(String dbName) { return toPath(dbName); } @Override public boolean dbExists(String dbName) { String dbPath = toPath(dbName); File db = new File(dbPath); return db.exists(); } }