--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.RAMAccessManager\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.access;\r
+\r
+import org.apache.derby.iapi.services.cache.Cacheable;\r
+import org.apache.derby.iapi.services.cache.CacheableFactory;\r
+import org.apache.derby.iapi.services.cache.CacheFactory;\r
+import org.apache.derby.iapi.services.cache.CacheManager;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+import org.apache.derby.iapi.services.context.ContextService;\r
+import org.apache.derby.iapi.services.daemon.Serviceable;\r
+import org.apache.derby.iapi.services.locks.LockFactory;\r
+import org.apache.derby.iapi.services.monitor.ModuleControl;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.property.PropertySetCallback;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;\r
+import org.apache.derby.iapi.store.access.conglomerate.ConglomerateFactory;\r
+import org.apache.derby.iapi.store.access.conglomerate.MethodFactory;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+import org.apache.derby.iapi.store.access.AccessFactory;\r
+import org.apache.derby.iapi.services.property.PropertyFactory;\r
+\r
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.store.access.TransactionInfo;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.ContainerKey;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.catalog.UUID;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.Attribute;\r
+\r
+import java.util.Dictionary;\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Properties;\r
+\r
+import java.io.Serializable;\r
+\r
+\r
+public abstract class RAMAccessManager\r
+ implements AccessFactory, \r
+ CacheableFactory, \r
+ ModuleControl, \r
+ PropertySetCallback\r
+{\r
+ /**************************************************************************\r
+ * Fields of the class\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ The raw store that this access manager uses.\r
+ **/\r
+ private RawStoreFactory rawstore;\r
+\r
+ /**\r
+ Hash table on primary implementation type.\r
+ **/\r
+ private Hashtable implhash;\r
+\r
+ /**\r
+ Hash table on primary format.\r
+ **/\r
+ private Hashtable formathash;\r
+\r
+ /**\r
+ Service properties. These are supplied from ModuleControl.boot(),\r
+ and ultimately come from the service.properties file.\r
+ By convention, these properties are passed down to all modules\r
+ booted by this one. If this module needs to pass specific instructions\r
+ to its sub-modules, it should create a new Properties object with\r
+ serviceProperties as its default (so that the rest of the modules\r
+ that are looking at it don't see the properties that this module\r
+ needs to add).\r
+ **/\r
+ private Properties serviceProperties;\r
+\r
+ /**\r
+ * Default locking policy for the entire system.\r
+ **/\r
+ LockingPolicy system_default_locking_policy;\r
+\r
+ /** \r
+ The object providing the properties like behaviour\r
+ that is transactional.\r
+ */\r
+ private PropertyConglomerate xactProperties;\r
+ private PropertyFactory pf;\r
+\r
+ protected LockingPolicy table_level_policy[];\r
+ protected LockingPolicy record_level_policy[];\r
+\r
+\r
+ /**\r
+ * A map of the implementation specific id to conglomerate object.\r
+ * <p>\r
+ * A map of the implementation specific id to conglomerate object.\r
+ * The id is encoded into the conglomerate number, and then used to\r
+ * pick the right implementation of the conglomerate. It is then\r
+ * up to the conglomerate implementation to retrieve it's stored \r
+ * representation from disk.\r
+ *\r
+ * An internal mapping of the encoding of conglomerate identity in the\r
+ * conglomerate number to the actual conglomerate implementation. Encoding\r
+ * this means that we can't dynamically add conglomerate implementations\r
+ * into the system, so when we want to do that this mapping will have to\r
+ * be more dynamic - but for now store knows exactly what implementations\r
+ * there are.\r
+ **/\r
+ protected ConglomerateFactory conglom_map[];\r
+\r
+ /**\r
+ * Cache of Conglomerate objects, keyed by conglom id. Used to speed up\r
+ * subsquent open of conglomerates, first open will need to call the \r
+ * conglomerate to read and return it's description.\r
+ **/\r
+ private CacheManager conglom_cache;\r
+\r
+ /**************************************************************************\r
+ * Constructors for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ public RAMAccessManager()\r
+ {\r
+ // Intialize the hash tables that hold the access methods that\r
+ // this access manager knows about.\r
+ implhash = new Hashtable();\r
+ formathash = new Hashtable();\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Private/Protected methods of This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Return the default locking policy for this access manager.\r
+ *\r
+ * @return the default locking policy for this accessmanager.\r
+ **/\r
+ protected LockingPolicy getDefaultLockingPolicy()\r
+ {\r
+ return(system_default_locking_policy);\r
+ }\r
+\r
+\r
+ RawStoreFactory getRawStore()\r
+ {\r
+ return rawstore;\r
+ }\r
+\r
+\r
+ PropertyConglomerate getTransactionalProperties()\r
+ {\r
+ return xactProperties;\r
+ }\r
+\r
+ private void boot_load_conglom_map()\r
+ throws StandardException\r
+ {\r
+ // System.out.println("before new code.");\r
+\r
+ conglom_map = new ConglomerateFactory[2];\r
+\r
+ // Find the appropriate factory for the desired implementation.\r
+ MethodFactory mfactory = findMethodFactoryByImpl("heap");\r
+\r
+ if (mfactory == null || !(mfactory instanceof ConglomerateFactory))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_CONGLOMERATE_TYPE, "heap");\r
+ }\r
+\r
+ conglom_map[ConglomerateFactory.HEAP_FACTORY_ID] = \r
+ (ConglomerateFactory) mfactory;\r
+\r
+ // Find the appropriate factory for the desired implementation.\r
+ mfactory = findMethodFactoryByImpl("BTREE");\r
+\r
+ if (mfactory == null || !(mfactory instanceof ConglomerateFactory))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_CONGLOMERATE_TYPE, "BTREE");\r
+ }\r
+ conglom_map[ConglomerateFactory.BTREE_FACTORY_ID] = \r
+ (ConglomerateFactory) mfactory;\r
+\r
+ // System.out.println("conglom_map[0] = " + conglom_map[0]);\r
+ // System.out.println("conglom_map[1] = " + conglom_map[1]);\r
+ }\r
+\r
+\r
+\r
+\r
+ /***************************************************************************\r
+ ** Abstract Methods of RAMAccessManager, interfaces that control locking\r
+ ** level of the system.\r
+ ****************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Return the locking level of the system.\r
+ * <p>\r
+ * This routine controls the lowest level of locking enabled for all locks\r
+ * for all tables accessed through this accessmanager. The concrete \r
+ * implementation may set this value always to table level locking for\r
+ * a client configuration, or it may set it to row level locking for a\r
+ * server configuration.\r
+ * <p>\r
+ * If TransactionController.MODE_RECORD is returned table may either be\r
+ * locked at table or row locking depending on the type of access expected\r
+ * (ie. level 3 will require table locking for heap scans.)\r
+ *\r
+ * @return TransactionController.MODE_TABLE if only table locking allowed,\r
+ * else returns TransactionController.MODE_RECORD.\r
+ *\r
+ **/\r
+ abstract protected int getSystemLockLevel();\r
+\r
+ /**\r
+ * Query property system to get the System lock level.\r
+ * <p>\r
+ * This routine will be called during boot after access has booted far \r
+ * enough, to allow access to the property conglomerate. This routine\r
+ * will call the property system and set the value to be returned by\r
+ * getSystemLockLevel().\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ abstract protected void bootLookupSystemLockLevel(\r
+ TransactionController tc)\r
+ throws StandardException;\r
+\r
+ /**************************************************************************\r
+ * Routines to map to/from conglomid/containerid:\r
+ **************************************************************************\r
+ */\r
+ private long conglom_nextid = 0;\r
+\r
+ /**\r
+ * Return next conglomid to try to add the container with.\r
+ * <p>\r
+ * The conglomerate number has 2 parts. The low 4 bits are used to \r
+ * encode the factory which "owns" the conglomerate. The high 60 bits\r
+ * are used as a normal unique id mechanism.\r
+ * <p>\r
+ * So for example if the next id to assign is 0x54 the following will\r
+ * be the conglomid:\r
+ * if a HEAP (factory 0) - 0x540\r
+ * if a BTREE (factory 1) - 0x541\r
+ *\r
+ * And the next id assigned will be:\r
+ * if a HEAP (factory 0) - 0x550\r
+ * if a BTREE (factory 1) - 0x551\r
+ *\r
+ * @param factory_type factory id as gotten from getConglomerateFactoryId()\r
+ *\r
+ * @return The identifier to be used to open the conglomerate later.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ protected long getNextConglomId(int factory_type)\r
+ throws StandardException\r
+ {\r
+ long conglomid;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // current code depends on this range, if we ever need to expand the\r
+ // range we can claim bits from the high order of the long.\r
+\r
+ SanityManager.ASSERT(factory_type >= 0x00 && factory_type <= 0x0f);\r
+ }\r
+\r
+ synchronized (conglom_cache)\r
+ {\r
+ if (conglom_nextid == 0)\r
+ {\r
+ // shift out the factory id and then add 1.\r
+ conglom_nextid = (rawstore.getMaxContainerId() >> 4) + 1;\r
+ }\r
+\r
+ conglomid = conglom_nextid++;\r
+ }\r
+\r
+ // shift in the factory id and then return the conglomid.\r
+ \r
+ return((conglomid << 4) | factory_type);\r
+ }\r
+\r
+ /**\r
+ * Bump the conglomid.\r
+ * <p>\r
+ * For some reason we have found that the give conglomid already exists\r
+ * in the directory so just bump the next conglomid to greater than this\r
+ * one. The algorithm to store and retrieve the last conglomid is not\r
+ * transactional as we don't want to pay the overhead for such an algorithm\r
+ * on every ddl statement - so it is possible to "lose" an update to the\r
+ * counter if we crash at an inopportune moment. In general the upper\r
+ * level store code will just handle the error from addContainer which \r
+ * says there already exists a conglom with that id, update the next\r
+ * conglomid and then try again.\r
+ * <p>\r
+ *\r
+ * @param conglomid The conglomid which already exists.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ // currently not used, but this is one idea on how to handle \r
+ // non-transactional update of the nextid field, just handle the error\r
+ // if we try to create a conglom and find the container already exists.\r
+ /*\r
+ private void handleConglomidExists(\r
+ long conglomid)\r
+ throws StandardException\r
+ {\r
+ synchronized (conglom_cache)\r
+ {\r
+ conglom_nextid = ((conglomid >> 4) + 1);\r
+ }\r
+ }\r
+ */\r
+\r
+ /**\r
+ * Given a conglomid, return the factory which "owns" it.\r
+ * <p>\r
+ * A simple lookup on the boot time built table which maps the low order\r
+ * 4 bits into which factory owns the conglomerate.\r
+ * <p>\r
+ *\r
+ * @param conglom_id The conglomerate id of the conglomerate to look up.\r
+ *\r
+ * @return The ConglomerateFactory which "owns" this conglomerate.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ private ConglomerateFactory getFactoryFromConglomId(\r
+ long conglom_id)\r
+ throws StandardException\r
+ {\r
+ try\r
+ {\r
+ return(conglom_map[((int) (0x0f & conglom_id))]);\r
+ }\r
+ catch (java.lang.ArrayIndexOutOfBoundsException e)\r
+ {\r
+ // just in case language passes in a bad factory id.\r
+ throw StandardException.newException(\r
+ SQLState.STORE_CONGLOMERATE_DOES_NOT_EXIST, \r
+ new Long(conglom_id));\r
+ }\r
+ }\r
+\r
+\r
+ /**************************************************************************\r
+ * Conglomerate Cache routines:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * ACCESSMANAGER CONGLOMERATE CACHE - \r
+ * <p>\r
+ * Every conglomerate in the system is described by an object which \r
+ * implements Conglomerate. This object basically contains the parameters\r
+ * which describe the metadata about the conglomerate that store needs\r
+ * to know - like types of columns, number of keys, number of columns, ...\r
+ * <p>\r
+ * It is up to each conglomerate to maintain it's own description, and\r
+ * it's factory must be able to read this info from disk and return it\r
+ * from the ConglomerateFactory.readConglomerate() interface.\r
+ * <p>\r
+ * This cache simply maintains an in memory copy of these conglomerate\r
+ * objects, key'd by conglomerate id. By caching, this avoids the cost\r
+ * of reading the conglomerate info from disk on each subsequent query\r
+ * which accesses the conglomerate.\r
+ * <p>\r
+ * The interfaces and internal routines which deal with this cache are:\r
+ * conglomCacheInit() - initializes the cache at boot time.\r
+ *\r
+ *\r
+ *\r
+ **/\r
+\r
+ /**\r
+ * Initialize the conglomerate cache.\r
+ * <p>\r
+ * Simply calls the cache manager to create the cache with some hard\r
+ * coded defaults for size.\r
+ * <p>\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ private void conglomCacheInit()\r
+ throws StandardException\r
+ {\r
+ // Get a cache factory to create the conglomerate cache.\r
+ CacheFactory cf = \r
+ (CacheFactory) Monitor.startSystemModule(\r
+ org.apache.derby.iapi.reference.Module.CacheFactory);\r
+\r
+ // Now create the conglomerate cache.\r
+\r
+ conglom_cache =\r
+ cf.newCacheManager(\r
+ this, AccessFactoryGlobals.CFG_CONGLOMDIR_CACHE, 200, 300);\r
+\r
+ }\r
+\r
+ /**\r
+ * Find a conglomerate by conglomid in the cache.\r
+ * <p>\r
+ * Look for a conglomerate given a conglomid. If in cache return it,\r
+ * otherwise fault in an entry by asking the owning factory to produce\r
+ * an entry.\r
+ * <p>\r
+ *\r
+ * @return The conglomerate object identified by "conglomid".\r
+ *\r
+ * @param conglomid The conglomerate id of the conglomerate to look up.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ /* package */ Conglomerate conglomCacheFind(\r
+ TransactionManager xact_mgr,\r
+ long conglomid)\r
+ throws StandardException\r
+ {\r
+ Conglomerate conglom = null;\r
+ Long conglomid_obj = new Long(conglomid);\r
+\r
+ synchronized (conglom_cache)\r
+ {\r
+ CacheableConglomerate cache_entry = \r
+ (CacheableConglomerate) conglom_cache.findCached(conglomid_obj);\r
+\r
+ if (cache_entry != null)\r
+ {\r
+ conglom = cache_entry.getConglom();\r
+ conglom_cache.release(cache_entry);\r
+\r
+ // SanityManager.DEBUG_PRINT("find", "find hit : " + conglomid);\r
+ }\r
+ else\r
+ {\r
+ // SanityManager.DEBUG_PRINT("find", "find miss: " + conglomid);\r
+\r
+ // If not in cache - ask the factory for it and insert it.\r
+\r
+ conglom = \r
+ getFactoryFromConglomId(conglomid).readConglomerate(\r
+ xact_mgr, new ContainerKey(0, conglomid));\r
+\r
+ if (conglom != null)\r
+ {\r
+ // on cache miss, put the missing conglom in the cache.\r
+ cache_entry = (CacheableConglomerate) \r
+ this.conglom_cache.create(conglomid_obj, conglom);\r
+ this.conglom_cache.release(cache_entry);\r
+ }\r
+ }\r
+ }\r
+\r
+ return(conglom);\r
+ }\r
+\r
+ /**\r
+ * Invalide the current Conglomerate Cache.\r
+ * <p>\r
+ * Abort of certain operations will invalidate the contents of the \r
+ * cache. Longer term we could just invalidate those entries, but\r
+ * for now just invalidate the whole cache.\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ /* package */ protected void conglomCacheInvalidate()\r
+ throws StandardException\r
+ {\r
+ synchronized (conglom_cache)\r
+ {\r
+ conglom_cache.ageOut();\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Update a conglomerate directory entry.\r
+ * <p>\r
+ * Update the Conglom column of the Conglomerate Directory. The \r
+ * Conglomerate with id "conglomid" is replaced by "new_conglom".\r
+ * <p>\r
+ *\r
+ * @param conglomid The conglomid of conglomerate to replace.\r
+ * @param new_conglom The new Conglom to update the conglom column to.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ /* package */ void conglomCacheUpdateEntry(\r
+ long conglomid, \r
+ Conglomerate new_conglom) \r
+ throws StandardException\r
+ {\r
+ Long conglomid_obj = new Long(conglomid);\r
+\r
+ synchronized (conglom_cache)\r
+ {\r
+ // remove the current entry\r
+ CacheableConglomerate conglom_entry = (CacheableConglomerate) \r
+ conglom_cache.findCached(conglomid_obj);\r
+\r
+ if (conglom_entry != null)\r
+ conglom_cache.remove(conglom_entry);\r
+\r
+ // insert the updated entry.\r
+ conglom_entry = (CacheableConglomerate) \r
+ conglom_cache.create(conglomid_obj, new_conglom);\r
+ conglom_cache.release(conglom_entry);\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Add a newly created conglomerate to the cache.\r
+ * <p>\r
+ *\r
+ * @param conglomid The conglomid of conglomerate to replace.\r
+ * @param conglom The Conglom to add.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ /* package */ void conglomCacheAddEntry(\r
+ long conglomid,\r
+ Conglomerate conglom)\r
+ throws StandardException\r
+ {\r
+ synchronized (conglom_cache)\r
+ {\r
+ // insert the updated entry.\r
+ CacheableConglomerate conglom_entry = (CacheableConglomerate) \r
+ conglom_cache.create(new Long(conglomid), conglom);\r
+ conglom_cache.release(conglom_entry);\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Remove an entry from the cache.\r
+ * <p>\r
+ *\r
+ * @param conglomid The conglomid of conglomerate to replace.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ /* package */ void conglomCacheRemoveEntry(long conglomid)\r
+ throws StandardException\r
+ {\r
+ synchronized (conglom_cache)\r
+ {\r
+ CacheableConglomerate conglom_entry = (CacheableConglomerate) \r
+ conglom_cache.findCached(new Long(conglomid));\r
+\r
+ if (conglom_entry != null)\r
+ conglom_cache.remove(conglom_entry);\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing AccessFactory Interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ Database creation finished. Tell RawStore.\r
+ @exception StandardException standard Derby error policy\r
+ */\r
+ public void createFinished() throws StandardException\r
+ {\r
+ rawstore.createFinished();\r
+ }\r
+\r
+ /**\r
+ Find an access method that implements a format type.\r
+ @see AccessFactory#findMethodFactoryByFormat\r
+ **/\r
+ public MethodFactory findMethodFactoryByFormat(UUID format)\r
+ {\r
+ MethodFactory factory;\r
+ \r
+ // See if there's an access method that supports the desired\r
+ // format type as its primary format type.\r
+ factory = (MethodFactory) formathash.get(format);\r
+ if (factory != null)\r
+ return factory;\r
+\r
+ // No primary format. See if one of the access methods\r
+ // supports it as a secondary format.\r
+ Enumeration e = formathash.elements();\r
+ while (e.hasMoreElements())\r
+ {\r
+ factory = (MethodFactory) e.nextElement();\r
+ if (factory.supportsFormat(format))\r
+ return factory;\r
+ }\r
+\r
+ // No such implementation.\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ Find an access method that implements an implementation type.\r
+ @see AccessFactory#findMethodFactoryByImpl\r
+ **/\r
+ public MethodFactory findMethodFactoryByImpl(String impltype)\r
+ throws StandardException\r
+ {\r
+ // See if there's an access method that supports the desired\r
+ // implementation type as its primary implementation type.\r
+ MethodFactory factory = (MethodFactory) implhash.get(impltype);\r
+ if (factory != null)\r
+ return factory;\r
+\r
+ // No primary implementation. See if one of the access methods\r
+ // supports the implementation type as a secondary.\r
+ Enumeration e = implhash.elements();\r
+ while (e.hasMoreElements())\r
+ {\r
+ factory = (MethodFactory) e.nextElement();\r
+ if (factory.supportsImplementation(impltype))\r
+ return factory;\r
+ }\r
+ factory = null;\r
+\r
+ // try and load an implementation. a new properties object needs\r
+ // to be created to hold the conglomerate type property, since\r
+ // that value is specific to the conglomerate we want to boot, not\r
+ // to the service as a whole\r
+ Properties conglomProperties = new Properties(serviceProperties);\r
+ conglomProperties.put(AccessFactoryGlobals.CONGLOM_PROP, impltype);\r
+\r
+ try {\r
+ factory = \r
+ (MethodFactory) Monitor.bootServiceModule(\r
+ false, this, MethodFactory.MODULE, \r
+ impltype, conglomProperties);\r
+ } catch (StandardException se) {\r
+ if (!se.getMessageId().equals(SQLState.SERVICE_MISSING_IMPLEMENTATION))\r
+ throw se;\r
+ }\r
+\r
+ conglomProperties = null;\r
+\r
+ if (factory != null) {\r
+ registerAccessMethod(factory);\r
+ return factory;\r
+ }\r
+\r
+ // No such implementation.\r
+ return null;\r
+ }\r
+\r
+ public LockFactory getLockFactory() {\r
+ return rawstore.getLockFactory();\r
+ }\r
+\r
+\r
+ public TransactionController getTransaction(\r
+ ContextManager cm)\r
+ throws StandardException\r
+ {\r
+ return getAndNameTransaction(cm, AccessFactoryGlobals.USER_TRANS_NAME);\r
+ }\r
+\r
+ public TransactionController getAndNameTransaction(\r
+ ContextManager cm, String transName)\r
+ throws StandardException\r
+ {\r
+ if (cm == null)\r
+ return null; // XXX (nat) should throw exception\r
+\r
+ // See if there's already a transaction context.\r
+ RAMTransactionContext rtc = (RAMTransactionContext)\r
+ cm.getContext(AccessFactoryGlobals.RAMXACT_CONTEXT_ID);\r
+\r
+ if (rtc == null)\r
+ {\r
+ // No transaction context. Create or find a raw store transaction,\r
+ // make a context for it, and push the context. Note this puts the\r
+ // raw store transaction context above the access context, which is\r
+ // required for error handling assumptions to be correct.\r
+ Transaction rawtran = rawstore.findUserTransaction(cm, transName);\r
+ RAMTransaction rt = new RAMTransaction(this, rawtran, null);\r
+\r
+ rtc = \r
+ new RAMTransactionContext(\r
+ cm, \r
+ AccessFactoryGlobals.RAMXACT_CONTEXT_ID,\r
+ rt, false /* abortAll */);\r
+\r
+ TransactionController tc = rtc.getTransaction();\r
+\r
+ if (xactProperties != null)\r
+ {\r
+ rawtran.setup(tc);\r
+ tc.commit();\r
+ }\r
+\r
+ rawtran.setDefaultLockingPolicy(system_default_locking_policy);\r
+\r
+ tc.commit();\r
+\r
+ return tc;\r
+ }\r
+ return rtc.getTransaction();\r
+ }\r
+\r
+ /**\r
+ * Start a global transaction.\r
+ * <p>\r
+ * Get a transaction controller with which to manipulate data within\r
+ * the access manager. Implicitly creates an access context.\r
+ * <p>\r
+ * Must only be called if no other transaction context exists in the\r
+ * current context manager. If another transaction exists in the context\r
+ * an exception will be thrown.\r
+ * <p>\r
+ * The (format_id, global_id, branch_id) triplet is meant to come exactly\r
+ * from a javax.transaction.xa.Xid. We don't use Xid so that the system\r
+ * can be delivered on a non-1.2 vm system and not require the javax classes\r
+ * in the path. \r
+ *\r
+ * @param cm The context manager for the current context.\r
+ * @param format_id the format id part of the Xid - ie. Xid.getFormatId().\r
+ * @param global_id the global transaction identifier part of XID - ie.\r
+ * Xid.getGlobalTransactionId().\r
+ * @param branch_id The branch qualifier of the Xid - ie. \r
+ * Xid.getBranchQaulifier()\r
+ * \r
+ * @exception StandardException Standard exception policy.\r
+ * @see TransactionController\r
+ **/\r
+ public /* XATransactionController */ Object startXATransaction(\r
+ ContextManager cm, \r
+ int format_id,\r
+ byte[] global_id,\r
+ byte[] branch_id)\r
+ throws StandardException\r
+ {\r
+ RAMTransaction xa_tc = null;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(global_id != null);\r
+ SanityManager.ASSERT(branch_id != null);\r
+ }\r
+\r
+ if (cm == null)\r
+ return null; // XXX (nat) should throw exception\r
+\r
+ // See if there's already a transaction context.\r
+ RAMTransactionContext rtc = (RAMTransactionContext) \r
+ cm.getContext(AccessFactoryGlobals.RAMXACT_CONTEXT_ID);\r
+\r
+ if (rtc == null)\r
+ {\r
+ // No transaction context. Create or find a raw store transaction,\r
+ // make a context for it, and push the context. Note this puts the\r
+ // raw store transaction context above the access context, which is\r
+ // required for error handling assumptions to be correct.\r
+ Transaction rawtran = \r
+ rawstore.startGlobalTransaction(\r
+ cm, format_id, global_id, branch_id);\r
+\r
+ xa_tc = new RAMTransaction(this, rawtran, null);\r
+\r
+ rtc = \r
+ new RAMTransactionContext(\r
+ cm, \r
+ AccessFactoryGlobals.RAMXACT_CONTEXT_ID,\r
+ xa_tc, false /* abortAll */);\r
+\r
+ // RESOLVE - an XA transaction can only commit once so, if we\r
+ // acquire readlocks.\r
+\r
+ if (xactProperties != null) \r
+ {\r
+ rawtran.setup(xa_tc);\r
+\r
+ // HACK - special support has been added to the commitNoSync\r
+ // of a global xact, to allow committing of read only xact, \r
+ // which will allow subsequent activity on the xact keeping\r
+ // the same global transaction id.\r
+ xa_tc.commitNoSync(\r
+ TransactionController.RELEASE_LOCKS |\r
+ TransactionController.READONLY_TRANSACTION_INITIALIZATION);\r
+ }\r
+\r
+ rawtran.setDefaultLockingPolicy(system_default_locking_policy);\r
+\r
+ // HACK - special support has been added to the commitNoSync\r
+ // of a global xact, to allow committing of read only xact, \r
+ // which will allow subsequent activity on the xact keeping\r
+ // the same global transaction id.\r
+ xa_tc.commitNoSync(\r
+ TransactionController.RELEASE_LOCKS |\r
+ TransactionController.READONLY_TRANSACTION_INITIALIZATION);\r
+ }\r
+ else\r
+ {\r
+ // throw an error.\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT(\r
+ "RAMTransactionContext found on stack.");\r
+ }\r
+\r
+ return(xa_tc);\r
+ }\r
+\r
+\r
+ /**\r
+ * Return the XAResourceManager associated with this AccessFactory.\r
+ * <p>\r
+ * Returns an object which can be used to implement the "offline" \r
+ * 2 phase commit interaction between the accessfactory and outstanding\r
+ * transaction managers taking care of in-doubt transactions.\r
+ *\r
+ * @return The XAResourceManager associated with this accessfactory.\r
+ *\r
+ **/\r
+ public /* XAResourceManager */ Object getXAResourceManager()\r
+ throws StandardException\r
+ {\r
+ return(rawstore.getXAResourceManager());\r
+ }\r
+\r
+ public void registerAccessMethod(MethodFactory factory)\r
+ {\r
+ // Put the access method's primary implementation type in\r
+ // a hash table so we can find it quickly.\r
+ implhash.put(factory.primaryImplementationType(), factory);\r
+\r
+ // Put the access method's primary format in a hash table\r
+ // so we can find it quickly.\r
+ formathash.put(factory.primaryFormat(), factory);\r
+ }\r
+\r
+ public boolean isReadOnly()\r
+ {\r
+ return rawstore.isReadOnly();\r
+ }\r
+\r
+ private void addPropertySetNotification(PropertySetCallback who, TransactionController tc) {\r
+\r
+ pf.addPropertySetNotification(who);\r
+ \r
+ // set up the initial values by calling the validate and apply methods.\r
+ // the map methods are not called as they will have been called\r
+ // at runtime when the user set the property.\r
+ Dictionary d = new Hashtable();\r
+ try {\r
+ xactProperties.getProperties(tc,d,false/*!stringsOnly*/,false/*!defaultsOnly*/);\r
+ } catch (StandardException se) {\r
+ return;\r
+ }\r
+\r
+ boolean dbOnly = PropertyUtil.isDBOnly(d);\r
+\r
+ who.init(dbOnly, d);\r
+ }\r
+\r
+ public TransactionInfo[] getTransactionInfo()\r
+ {\r
+ return rawstore.getTransactionInfo();\r
+ }\r
+\r
+ public void freeze() throws StandardException\r
+ {\r
+ rawstore.freeze();\r
+ }\r
+\r
+ public void unfreeze() throws StandardException\r
+ {\r
+ rawstore.unfreeze();\r
+ }\r
+\r
+ public void backup(\r
+ String backupDir, \r
+ boolean wait) \r
+ throws StandardException\r
+ {\r
+ rawstore.backup(backupDir, wait);\r
+ }\r
+\r
+\r
+ public void backupAndEnableLogArchiveMode(\r
+ String backupDir, \r
+ boolean deleteOnlineArchivedLogFiles,\r
+ boolean wait)\r
+ throws StandardException \r
+ {\r
+ rawstore.backupAndEnableLogArchiveMode(backupDir, \r
+ deleteOnlineArchivedLogFiles, \r
+ wait);\r
+ }\r
+\r
+ public void disableLogArchiveMode(boolean deleteOnlineArchivedLogFiles)\r
+ throws StandardException\r
+ {\r
+ rawstore.disableLogArchiveMode(deleteOnlineArchivedLogFiles);\r
+ }\r
+\r
+\r
+\r
+ public void checkpoint() throws StandardException\r
+ {\r
+ rawstore.checkpoint();\r
+ }\r
+\r
+ public void waitForPostCommitToFinishWork()\r
+ {\r
+ rawstore.getDaemon().waitUntilQueueIsEmpty();\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing ModuleControl Interface:\r
+ **************************************************************************\r
+ */\r
+ public void boot(boolean create, Properties startParams)\r
+ throws StandardException\r
+ {\r
+ this.serviceProperties = startParams;\r
+\r
+ boot_load_conglom_map();\r
+\r
+ if (create)\r
+ {\r
+ // if we are creating the db, then just start the conglomid's at\r
+ // 1, and proceed from there. If not create, we delay \r
+ // initialization of this until the first ddl which needs a new\r
+ // id.\r
+ conglom_nextid = 1;\r
+ }\r
+\r
+ // Access depends on a Raw Store implementations. Load it.\r
+ //\r
+ rawstore = (RawStoreFactory) Monitor.bootServiceModule(\r
+ create, this, RawStoreFactory.MODULE, serviceProperties);\r
+\r
+ // Note: we also boot this module here since we may start Derby\r
+ // system from store access layer, as some of the unit test case,\r
+ // not from JDBC layer.(See\r
+ // /protocol/Database/Storage/Access/Interface/T_AccessFactory.java)\r
+ // If this module has already been booted by the JDBC layer, this will \r
+ // have no effect at all.\r
+ Monitor.bootServiceModule(\r
+ create, this, org.apache.derby.iapi.reference.Module.PropertyFactory, \r
+ startParams);\r
+\r
+ // Create the in-memory conglomerate directory\r
+\r
+ conglomCacheInit();\r
+\r
+ // Read in the conglomerate directory from the conglom conglom\r
+ // Create the conglom conglom from within a separate system xact\r
+ RAMTransaction tc =\r
+ (RAMTransaction) getAndNameTransaction(\r
+ ContextService.getFactory().getCurrentContextManager(),\r
+ AccessFactoryGlobals.USER_TRANS_NAME);\r
+\r
+ // looking up lock_mode is dependant on access booting, but\r
+ // some boot routines need lock_mode and\r
+ // system_default_locking_policy, so during boot do table level\r
+ // locking and then look up the "right" locking level.\r
+\r
+ int lock_mode = LockingPolicy.MODE_CONTAINER;\r
+\r
+ system_default_locking_policy =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ lock_mode,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true);\r
+\r
+\r
+ // RESOLVE - code reduction - get rid of this table, and somehow\r
+ // combine it with the raw store one.\r
+\r
+ table_level_policy = new LockingPolicy[6];\r
+\r
+ table_level_policy[TransactionController.ISOLATION_NOLOCK] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_NOLOCK, true);\r
+\r
+ table_level_policy[TransactionController.ISOLATION_READ_UNCOMMITTED] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_READ_UNCOMMITTED, true);\r
+\r
+ table_level_policy[TransactionController.ISOLATION_READ_COMMITTED] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_READ_COMMITTED, true);\r
+\r
+ table_level_policy[TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,\r
+ true);\r
+\r
+ table_level_policy[TransactionController.ISOLATION_REPEATABLE_READ] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_REPEATABLE_READ, true);\r
+\r
+ table_level_policy[TransactionController.ISOLATION_SERIALIZABLE] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true);\r
+\r
+ record_level_policy = new LockingPolicy[6];\r
+\r
+ record_level_policy[TransactionController.ISOLATION_NOLOCK] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_NOLOCK, true);\r
+\r
+ record_level_policy[TransactionController.ISOLATION_READ_UNCOMMITTED] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_READ_UNCOMMITTED, true);\r
+\r
+ record_level_policy[TransactionController.ISOLATION_READ_COMMITTED] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_READ_COMMITTED, true);\r
+\r
+ record_level_policy[TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,\r
+ true);\r
+\r
+ record_level_policy[TransactionController.ISOLATION_REPEATABLE_READ] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_REPEATABLE_READ, true);\r
+\r
+ record_level_policy[TransactionController.ISOLATION_SERIALIZABLE] =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true);\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ for (int i = 0;\r
+ i < TransactionController.ISOLATION_SERIALIZABLE;\r
+ i++)\r
+ {\r
+ SanityManager.ASSERT(\r
+ table_level_policy[i] != null,\r
+ "table_level_policy[" + i + "] is null");\r
+ SanityManager.ASSERT(\r
+ record_level_policy[i] != null,\r
+ "record_level_policy[" + i + "] is null");\r
+ }\r
+ }\r
+\r
+ tc.commit();\r
+\r
+ // set up the property validation\r
+ pf = (PropertyFactory) \r
+ Monitor.findServiceModule(\r
+ this, org.apache.derby.iapi.reference.Module.PropertyFactory);\r
+\r
+ // set up the transaction properties. On J9, over NFS, runing on a\r
+ // power PC coprossor, the directories were created fine, but create\r
+ // db would fail when trying to create this first file in seg0.\r
+ xactProperties = new PropertyConglomerate(tc, create, startParams, pf);\r
+\r
+ // see if there is any properties that raw store needs to know\r
+ // about\r
+ rawstore.getRawStoreProperties(tc);\r
+\r
+ // now that access and raw store are booted, do the property lookup\r
+ // which may do conglomerate access.\r
+ bootLookupSystemLockLevel(tc);\r
+\r
+ lock_mode =\r
+ (getSystemLockLevel() == TransactionController.MODE_TABLE ?\r
+ LockingPolicy.MODE_CONTAINER : LockingPolicy.MODE_RECORD);\r
+\r
+ system_default_locking_policy =\r
+ tc.getRawStoreXact().newLockingPolicy(\r
+ lock_mode,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true);\r
+\r
+ // set up the callbacl for the lock manager with initialization\r
+ addPropertySetNotification(getLockFactory(), tc);\r
+\r
+ // make sure user cannot change these properties\r
+ addPropertySetNotification(this,tc);\r
+\r
+ tc.commit();\r
+\r
+ tc.destroy();\r
+ tc = null;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // RESOLVE - (mikem) currently these constants need to be the\r
+ // same, but for modularity reasons there are 2 sets. Probably\r
+ // should only be one set. For now just make sure they are the\r
+ // same value.\r
+ SanityManager.ASSERT(\r
+ TransactionController.OPENMODE_USE_UPDATE_LOCKS ==\r
+ ContainerHandle.MODE_USE_UPDATE_LOCKS);\r
+ SanityManager.ASSERT(\r
+ TransactionController.OPENMODE_SECONDARY_LOCKED ==\r
+ ContainerHandle.MODE_SECONDARY_LOCKED);\r
+ SanityManager.ASSERT(\r
+ TransactionController.OPENMODE_BASEROW_INSERT_LOCKED ==\r
+ ContainerHandle.MODE_BASEROW_INSERT_LOCKED);\r
+ SanityManager.ASSERT(\r
+ TransactionController.OPENMODE_FORUPDATE ==\r
+ ContainerHandle.MODE_FORUPDATE);\r
+ SanityManager.ASSERT(\r
+ TransactionController.OPENMODE_FOR_LOCK_ONLY ==\r
+ ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY);\r
+ }\r
+ }\r
+\r
+ public void stop()\r
+ {\r
+ }\r
+\r
+ /* Methods of the PropertySetCallback interface */\r
+\r
+ // This interface is implemented to ensure the user cannot change the\r
+ // encryption provider or algorithm.\r
+\r
+ public void init(boolean dbOnly, Dictionary p)\r
+ {\r
+ }\r
+\r
+ public boolean validate(String key, Serializable value, Dictionary p)\r
+ throws StandardException\r
+ {\r
+ if (key.equals(Attribute.CRYPTO_ALGORITHM))\r
+ {\r
+ throw StandardException.newException(SQLState.ENCRYPTION_NOCHANGE_ALGORITHM);\r
+ }\r
+ if (key.equals(Attribute.CRYPTO_PROVIDER))\r
+ {\r
+ throw StandardException.newException(SQLState.ENCRYPTION_NOCHANGE_PROVIDER);\r
+ }\r
+ return true;\r
+ }\r
+\r
+ public Serviceable apply(String key, Serializable value, Dictionary p)\r
+ throws StandardException\r
+ {\r
+ return null;\r
+ }\r
+\r
+ public Serializable map(String key, Serializable value, Dictionary p)\r
+ throws StandardException\r
+ {\r
+ return null;\r
+ }\r
+\r
+ // ///////////////////////////////////////////////////////////////\r
+\r
+ /*\r
+ ** CacheableFactory interface\r
+ */\r
+\r
+ public Cacheable newCacheable(CacheManager cm) {\r
+ return new CacheableConglomerate();\r
+ }\r
+\r
+}\r