|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.mdr.persistence.btreeimpl.btreestorage; import java.io.*; import java.text.*; import java.util.*; import org.netbeans.mdr.persistence.btreeimpl.btreeindex.*; import org.netbeans.mdr.persistence.*; import org.netbeans.mdr.util.Logger; /** * This class implements Storage using Btree files. Almost all implementation * is in BtreeDatabase, which see. */ public class BtreeStorage implements Storage { /* Key used to store value of @link #storageNumbersCounter. */ private static final String COUNTER_KEY = "counter"; /* Suffix of the name of SinglevaluedIndex used to store storage ids -> codes mapping. */ private static final String MAP1_INDEX_PREFIX = "storageIds:"; /* Suffix of the name of SinglevaluedIndex used to store storage codes -> ids mapping. */ private static final String MAP2_INDEX_PREFIX = "storageCodes:"; /* The btree database we have opened */ private BtreeDatabase btreeDB; /*The cached mofid entry type info */ private transient EntryTypeInfo mofIdEntryTypeInfo; /*The cached mofid class code */ private transient int mofIdClassCode; /*Buffer used for reading mofids */ private transient byte[] buffer = new byte[8]; /* Our MOFID generator */ MofidGenerator gen; /* The name of our database */ private final String btreeDBName; String storageUUID; /* Object resolver */ private ObjectResolver resolver; /* Index storing storageId -> code of storageId mapping */ private SinglevaluedIndex storageIdsMap; /* Index storing code of storageId -> storageId mapping */ private SinglevaluedIndex storageCodesMap; /* Value of the last used code. */ private int storageNumbersCounter; /* Cache for storageId -> integer mapping. */ private HashMap tempMap = null; /* Cache for integer -> storageId mapping. */ private HashMap tempMap2 = null; private final Map properties; /** Create a BtreeStorage object. Note that this does not create * or open the Btree repository * @param name the name of the btree. This will be the base name * for the btree files */ public BtreeStorage(String name, Map properties) { this.properties = properties; Logger.getDefault().log("DATABASE: " + name); btreeDBName = name; storageUUID = (String) properties.get(BtreeFactory.STORAGE_UUID); if (storageUUID != null) Logger.getDefault().log("Storage UUID: " + storageUUID); } Object getProperty(String name) { return properties.get(name); } /** Return our name */ public String getName() { return btreeDBName; } /** Returns storage id */ public synchronized String getStorageId() { return gen.getMofidPrefix(); } public synchronized long getSerialNumber () { return gen.getNextMofid(); } /** determine if the btree currently exists * @return true if it exists */ public boolean exists() { return BtreeDatabase.exists(btreeDBName); } /** delete the btree repository. * @return true if, at method end, there is no repository. false if * the repository exists but could not be deleted for any reason */ public synchronized boolean delete() throws StorageException { checkRepositoryClosed(); return BtreeDatabase.delete(btreeDBName); } /** Create btree repository * @param replace whether to replace an existing repository * @exception StorageException on any error creating the repository */ public synchronized void create(boolean replace, ObjectResolver resolver) throws StorageException { checkRepositoryClosed(); if (exists()) { if (replace) { if (!delete()) { throw new StorageBadRequestException( MessageFormat.format( "Unable to delete btree repository {0}", new Object[] {btreeDBName} ) ); } } else { throw new StorageBadRequestException( MessageFormat.format( "Btree repository {0} already exists", new Object[] {btreeDBName} ) ); } } this.resolver = resolver; btreeDB = new BtreeDatabase(btreeDBName, this, true); gen = btreeDB.getMofidGenerator(); storageIdsMap = createSinglevaluedIndex (MAP1_INDEX_PREFIX, Storage.EntryType.STRING, Storage.EntryType.INT); storageCodesMap = createSinglevaluedIndex (MAP2_INDEX_PREFIX, Storage.EntryType.INT, Storage.EntryType.STRING); } /** Open a btree MDR * @param createIfNoExist whether to create the repository if it * doesn't exist * @exception StorageException on any error opening or creating * the repository */ public synchronized void open(boolean createIfNoExist, ObjectResolver resolver) throws StorageException { checkRepositoryClosed(); if (exists()) { this.resolver = resolver; btreeDB = new BtreeDatabase(btreeDBName, this, false); gen = btreeDB.getMofidGenerator(); storageIdsMap = getSinglevaluedIndex (MAP1_INDEX_PREFIX); storageCodesMap = getSinglevaluedIndex (MAP2_INDEX_PREFIX); return; } if (createIfNoExist) { create(false, resolver); return; } throw new StorageBadRequestException( MessageFormat.format( "Btree repository {0} does not exist", new Object[] {btreeDBName} ) ); } /** close the btree repository. This does not commit any outstanding * changes. */ public synchronized void close() throws StorageException { checkRepositoryOpen(); btreeDB.close(); btreeDB = null; gen = null; tempMap = null; } /** Return the primary index (the BtreeDatabase) */ public synchronized SinglevaluedIndex getPrimaryIndex() throws StorageException { checkRepositoryOpen(); return btreeDB; } /** Create index that holds exactly one value for each key. * @return created index * @param name name of the index * @param keyType type of keys in the index * @param valueType type of values in the index */ public synchronized SinglevaluedIndex createSinglevaluedIndex(String name, Storage.EntryType keyType, Storage.EntryType valueType) throws StorageException { checkRepositoryOpen(); SinglevaluedBtree index = new SinglevaluedBtree(name, keyType, valueType, new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE)); btreeDB.addIndex(name, index, new MOFID(this)); return index; } /** Create index that holds sorted set of values for each key. * @return created index * @param name name of the index * @param keyType type of keys in the index * @param valueType type of values in the index * @param unique true if values associated with one key do not contain duplicates */ public synchronized MultivaluedOrderedIndex createMultivaluedOrderedIndex(String name, Storage.EntryType keyType, Storage.EntryType valueType, boolean unique) throws StorageException { checkRepositoryOpen(); MultivaluedOrderedBtree index = new MultivaluedOrderedBtree(name, keyType, valueType, unique, new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE)); btreeDB.addIndex(name, index, new MOFID(this)); return index; } /** Create index that hold a set of values for each key. Elements in one Multivalued are * not sorted. Set does not contain duplicate values. * @return created index * @param name name of the index * @param keyType type of keys in the index * @param valueType type of values in the index * @param unique true if values associated with one key do not contain duplicates */ public synchronized MultivaluedIndex createMultivaluedIndex(String name, Storage.EntryType keyType, Storage.EntryType valueType, boolean unique) throws StorageException { checkRepositoryOpen(); MultivaluedBtree index = new MultivaluedBtree(name, keyType, valueType, unique, new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE)); btreeDB.addIndex(name, index, new MOFID(this)); return index; } /** Retrieve index by name. * @param name name of the index * @return index of the specified name */ public synchronized Index getIndex(String name) throws StorageException { checkRepositoryOpen(); return (Index) btreeDB.fetchIndex(name); } /** Retrieve index by name. * @param name name of the index * @return index of the specified name and type */ public synchronized SinglevaluedIndex getSinglevaluedIndex(String name) throws StorageException { Object idx = getIndex(name); checkIndexType(idx, name, SinglevaluedIndex.class); return (SinglevaluedIndex)idx; } /** Retrieve index by name. * @param name name of the index * @return index of the specified name and type */ public synchronized MultivaluedIndex getMultivaluedIndex(String name) throws StorageException { Object idx = getIndex(name); checkIndexType(idx, name, MultivaluedIndex.class); return (MultivaluedIndex)idx; } /** Retrieve index by name. * @param name name of the index * @return index of the specified name and type */ public synchronized MultivaluedOrderedIndex getMultivaluedOrderedIndex(String name) throws StorageException { Object idx = getIndex(name); checkIndexType(idx, name, MultivaluedOrderedIndex.class); return (MultivaluedOrderedIndex)idx; } /** Delete index. * @param name name of the index */ public synchronized void dropIndex(String name) throws StorageException { checkRepositoryOpen(); btreeDB.dropIndex(name); } /** Notify the Storage that state of the object will be changed. * @param key key of object that will be changed */ public void objectStateWillChange(Object key) throws StorageException { // do nothing } /** Notify the Storage that state of the object was changed. * @param key key of object that was changed */ public synchronized void objectStateChanged(Object key) throws StorageException { checkRepositoryOpen(); btreeDB.objectStateChanged(key); } /** Save all objects changed since this method was last call. * This operation implements transactions on the storage. * It must either whole complete or whole fail. */ public synchronized void commitChanges() throws StorageException { checkRepositoryOpen(); btreeDB.commitChanges(); } /** Discard all changes since commitChanges() method was last called. * This operation implements transactions on the storage. * It must either whole complete or whole fail. * Note that, after this method completes, the persistent MDR and * any modified objects in memory are inconsistent, so it should * be followed shortly by program exit. */ public synchronized void rollBackChanges() throws StorageException { checkRepositoryOpen(); btreeDB.rollbackChanges(); close(); open(false, resolver); } /** * Shutdowns btree databes (i.e. flushes cached commited data in transaction cache). */ public synchronized void shutDown() throws StorageException { checkRepositoryOpen(); btreeDB.shutDown(); } /** Returns true if the storage supports more than one index with type * {@link Entrytype.STREAMABLE} * @return true if the storage supports more than one index with type * {@link Entrytype.STREAMABLE} */ public boolean supportsMultipleStorableIndexes() { /* Btree supports only one primary index */ return false; } public synchronized void writeMOFID (java.io.OutputStream outputStream, MOFID mofId) throws StorageException { // this looks like it is not needed - MOFID's class is always org.netbeans.mdr.persistence.MOFID // if (this.mofIdClassCode == -1) { // this.mofIdClassCode = this.btreeDB.getClassCode (mofId.getClass()); // } DataOutputStream out = null; if (outputStream instanceof DataOutputStream) out = (DataOutputStream) outputStream; else out = new DataOutputStream (outputStream); /* try { out.writeInt (this.mofIdClassCode); } catch (IOException ioException) { throw new StorageIOException (ioException); } this.writeMOFIDData (out, mofId); */ // optimized write: long mofidData = mofId.getSerialNumber(); String storageId = mofId.getStorageID(); short s; if (this.getStorageId().equals(storageId)) { s = (short) BtreeFactory.SAME_PREFIX_CODE; } else if (BtreeFactory.INTERNAL_PREFIX.equals(storageId)) { s = (short) BtreeFactory.INTERNAL_PREFIX_CODE; } else { s = (short) this.storageIdToNumber(storageId); } mofidData |= ((long) s) << 48; try { while (mofidData != 0) { int b = ((int) mofidData) & 0x7f; mofidData >>>= 7; if (mofidData != 0) b |= 0x80; out.write(b); } } catch (IOException e) { throw (StorageException) Logger.getDefault().annotate(new StorageIOException(e), e); } } public final void writeMOFIDData (java.io.OutputStream out, MOFID mofid) throws StorageException { try { out.write (this.getMOFIDData(mofid)); } catch (IOException ioException) { throw new StorageIOException (ioException); } } public synchronized final byte[] getMOFIDData (MOFID mofid) throws StorageException { if (this.mofIdEntryTypeInfo == null) { this.mofIdEntryTypeInfo = EntryTypeInfo.getEntryTypeInfo(Storage.EntryType.MOFID,this); } return this.mofIdEntryTypeInfo.toBuffer(mofid); } // this method is always called from a thread safe code (readStreamable) // thus it does not need to be synchronized // if it shows up that it needs to be synchronized, a separate lock should be used // for that to avoid deadlocks public synchronized MOFID readMOFID (java.io.InputStream inputStream) throws StorageException { DataInputStream in = null; if (inputStream instanceof DataInputStream) in = (DataInputStream) inputStream; else in = new DataInputStream (inputStream); // optimized read: long mofidData = 0; try { int b; int i = 0; do { b = in.read(); mofidData |= ((long) (b & 0x7f)) << (i * 7); i++; } while ((b & 0x80) != 0); int storageNumber = (int) (mofidData >> 48); String storageId; switch (storageNumber) { case BtreeFactory.INTERNAL_PREFIX_CODE: storageId = BtreeFactory.INTERNAL_PREFIX; break; case BtreeFactory.SAME_PREFIX_CODE: storageId = this.getStorageId(); break; default: storageId = this.numberToStorageId(storageNumber); } return new MOFID (mofidData & 0xffffffffffffL, storageId); } catch (IOException e) { throw (StorageException) Logger.getDefault().annotate(new StorageIOException(e), e); } /* let's rather do it in optimized way above try { int mofIdClassCode = in.readInt (); if (mofIdClassCode != this.mofIdClassCode) throw new IllegalStateException (); return this.readMOFIDData (in); }catch (IOException ioException) { throw new StorageIOException (ioException); } */ } public synchronized final MOFID readMOFIDData (java.io.InputStream in) throws StorageException { if (this.mofIdEntryTypeInfo == null) { this.mofIdEntryTypeInfo = EntryTypeInfo.getEntryTypeInfo(Storage.EntryType.MOFID, this); } try { in.read (this.buffer); return (MOFID) mofIdEntryTypeInfo.fromBuffer (this.buffer); }catch (IOException ioException) { throw new StorageIOException (ioException); } } /** Return the MOFID generator for this repository */ public synchronized MofidGenerator getMofidGenerator() { return btreeDB.getMofidGenerator(); } /** Return the map of MOFID UUIDs we know about */ public synchronized Map getMofidMap() { return btreeDB.getMofidMap(); } /** * Initializes storage id <-> storage code mapping. */ private void initStorageIdsMap () throws StorageException { Object value = storageIdsMap.getIfExists (COUNTER_KEY); if (value == null) { storageNumbersCounter = BtreeFactory.FIRST_EXTERNAL_CODE; storageIdsMap.put (COUNTER_KEY, value = new Integer (storageNumbersCounter)); } storageNumbersCounter = ((Integer) value).intValue (); tempMap = new HashMap (); tempMap2 = new HashMap (); } /** * Maps an external storage prefix to integer. */ public synchronized int storageIdToNumber (String storageId) throws StorageException { Object value; if (tempMap == null) initStorageIdsMap (); value = tempMap.get (storageId); if (value == null) { value = storageIdsMap.getIfExists (storageId); if (value == null) { storageNumbersCounter++; value = new Integer (storageNumbersCounter); storageIdsMap.replace (COUNTER_KEY, value); storageIdsMap.put (storageId, value); storageCodesMap.put (value, storageId); } tempMap.put (storageId, value); } return ((Integer) value).intValue (); } /** * Resolves external storage number coded by an integer. */ public synchronized String numberToStorageId (int number) throws StorageException { Object value; if (tempMap == null) initStorageIdsMap (); Object code = new Integer (number); value = tempMap2.get (code); if (value == null) { value = storageCodesMap.get (code); if (value == null) { throw new StorageBadRequestException ("Unknown storage code requested: " + number); } tempMap2.put (code, value); } return (String) value; } /** * Delegates resolving of external mof ids on the object resolver. */ public synchronized Object resolveObject (MOFID key) throws StorageException { return resolver.resolve (key.getStorageID(), key); } /* check that the returned index is of the correct type */ private void checkIndexType(Object idx, String idxName, Class idxType) throws StorageException { if (!idxType.isInstance(idx)) { throw new StorageBadRequestException( MessageFormat.format("{0} is not a {1}", new Object[] { idxName, idxType.getName() } ) ); } } /* We only operate on one repository at a time */ private void checkRepositoryClosed() throws StorageException { if (btreeDB != null) { throw new StorageBadRequestException( MessageFormat.format( "The btree repository {0} is already open", new Object[] { btreeDBName} ) ); } } /* Many operations aren't possible if the repsitory isn't open */ private void checkRepositoryOpen() throws StorageException { if (btreeDB == null) { throw new StorageBadRequestException( MessageFormat.format( "The btree repository {0} is not open", new Object[] { btreeDBName} ) ); } } /* Fix this when secondary indices are supported */ private void notSupported() throws StorageException { throw new StorageBadRequestException( "Secondary indices are not supported!"); } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.