0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.store.access.RAMAccessManager
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.store.access;
0023:
0024: import org.apache.derby.iapi.services.cache.Cacheable;
0025: import org.apache.derby.iapi.services.cache.CacheableFactory;
0026: import org.apache.derby.iapi.services.cache.CacheFactory;
0027: import org.apache.derby.iapi.services.cache.CacheManager;
0028:
0029: import org.apache.derby.iapi.services.context.ContextManager;
0030: import org.apache.derby.iapi.services.context.ContextService;
0031: import org.apache.derby.iapi.services.daemon.Serviceable;
0032: import org.apache.derby.iapi.services.locks.LockFactory;
0033: import org.apache.derby.iapi.services.monitor.ModuleControl;
0034: import org.apache.derby.iapi.services.monitor.Monitor;
0035: import org.apache.derby.iapi.services.property.PropertySetCallback;
0036:
0037: import org.apache.derby.iapi.services.sanity.SanityManager;
0038: import org.apache.derby.iapi.services.io.FormatIdUtil;
0039:
0040: import org.apache.derby.iapi.error.StandardException;
0041:
0042: import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
0043: import org.apache.derby.iapi.store.access.conglomerate.ConglomerateFactory;
0044: import org.apache.derby.iapi.store.access.conglomerate.MethodFactory;
0045: import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
0046: import org.apache.derby.iapi.services.property.PropertyUtil;
0047: import org.apache.derby.iapi.store.access.AccessFactory;
0048: import org.apache.derby.iapi.services.property.PropertyFactory;
0049:
0050: import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
0051: import org.apache.derby.iapi.store.access.TransactionController;
0052: import org.apache.derby.iapi.store.access.TransactionInfo;
0053:
0054: import org.apache.derby.iapi.store.raw.ContainerHandle;
0055: import org.apache.derby.iapi.store.raw.ContainerKey;
0056: import org.apache.derby.iapi.store.raw.LockingPolicy;
0057: import org.apache.derby.iapi.store.raw.RawStoreFactory;
0058: import org.apache.derby.iapi.store.raw.Transaction;
0059:
0060: import org.apache.derby.catalog.UUID;
0061:
0062: import org.apache.derby.iapi.services.io.FormatableHashtable;
0063: import org.apache.derby.iapi.reference.SQLState;
0064: import org.apache.derby.iapi.reference.Attribute;
0065:
0066: import java.util.Dictionary;
0067: import java.util.Enumeration;
0068: import java.util.Hashtable;
0069: import java.util.Properties;
0070:
0071: import java.io.File;
0072: import java.io.Serializable;
0073:
0074: public abstract class RAMAccessManager implements AccessFactory,
0075: CacheableFactory, ModuleControl, PropertySetCallback {
0076: /**************************************************************************
0077: * Fields of the class
0078: **************************************************************************
0079: */
0080:
0081: /**
0082: The raw store that this access manager uses.
0083: **/
0084: private RawStoreFactory rawstore;
0085:
0086: /**
0087: Hash table on primary implementation type.
0088: **/
0089: private Hashtable implhash;
0090:
0091: /**
0092: Hash table on primary format.
0093: **/
0094: private Hashtable formathash;
0095:
0096: /**
0097: Service properties. These are supplied from ModuleControl.boot(),
0098: and ultimately come from the service.properties file.
0099: By convention, these properties are passed down to all modules
0100: booted by this one. If this module needs to pass specific instructions
0101: to its sub-modules, it should create a new Properties object with
0102: serviceProperties as its default (so that the rest of the modules
0103: that are looking at it don't see the properties that this module
0104: needs to add).
0105: **/
0106: private Properties serviceProperties;
0107:
0108: /**
0109: * Default locking policy for the entire system.
0110: **/
0111: LockingPolicy system_default_locking_policy;
0112:
0113: /**
0114: The object providing the properties like behaviour
0115: that is transactional.
0116: */
0117: private PropertyConglomerate xactProperties;
0118: private PropertyFactory pf;
0119:
0120: protected LockingPolicy table_level_policy[];
0121: protected LockingPolicy record_level_policy[];
0122:
0123: /**
0124: * A map of the implementation specific id to conglomerate object.
0125: * <p>
0126: * A map of the implementation specific id to conglomerate object.
0127: * The id is encoded into the conglomerate number, and then used to
0128: * pick the right implementation of the conglomerate. It is then
0129: * up to the conglomerate implementation to retrieve it's stored
0130: * representation from disk.
0131: *
0132: * An internal mapping of the encoding of conglomerate identity in the
0133: * conglomerate number to the actual conglomerate implementation. Encoding
0134: * this means that we can't dynamically add conglomerate implementations
0135: * into the system, so when we want to do that this mapping will have to
0136: * be more dynamic - but for now store knows exactly what implementations
0137: * there are.
0138: **/
0139: protected ConglomerateFactory conglom_map[];
0140:
0141: /**
0142: * Cache of Conglomerate objects, keyed by conglom id. Used to speed up
0143: * subsquent open of conglomerates, first open will need to call the
0144: * conglomerate to read and return it's description.
0145: **/
0146: private CacheManager conglom_cache;
0147:
0148: /**************************************************************************
0149: * Constructors for This class:
0150: **************************************************************************
0151: */
0152:
0153: public RAMAccessManager() {
0154: // Intialize the hash tables that hold the access methods that
0155: // this access manager knows about.
0156: implhash = new Hashtable();
0157: formathash = new Hashtable();
0158: }
0159:
0160: /**************************************************************************
0161: * Private/Protected methods of This class:
0162: **************************************************************************
0163: */
0164:
0165: /**
0166: * Return the default locking policy for this access manager.
0167: *
0168: * @return the default locking policy for this accessmanager.
0169: **/
0170: protected LockingPolicy getDefaultLockingPolicy() {
0171: return (system_default_locking_policy);
0172: }
0173:
0174: RawStoreFactory getRawStore() {
0175: return rawstore;
0176: }
0177:
0178: PropertyConglomerate getTransactionalProperties() {
0179: return xactProperties;
0180: }
0181:
0182: private void boot_load_conglom_map() throws StandardException {
0183: // System.out.println("before new code.");
0184:
0185: conglom_map = new ConglomerateFactory[2];
0186:
0187: // Find the appropriate factory for the desired implementation.
0188: MethodFactory mfactory = findMethodFactoryByImpl("heap");
0189:
0190: if (mfactory == null
0191: || !(mfactory instanceof ConglomerateFactory)) {
0192: throw StandardException.newException(
0193: SQLState.AM_NO_SUCH_CONGLOMERATE_TYPE, "heap");
0194: }
0195:
0196: conglom_map[ConglomerateFactory.HEAP_FACTORY_ID] = (ConglomerateFactory) mfactory;
0197:
0198: // Find the appropriate factory for the desired implementation.
0199: mfactory = findMethodFactoryByImpl("BTREE");
0200:
0201: if (mfactory == null
0202: || !(mfactory instanceof ConglomerateFactory)) {
0203: throw StandardException.newException(
0204: SQLState.AM_NO_SUCH_CONGLOMERATE_TYPE, "BTREE");
0205: }
0206: conglom_map[ConglomerateFactory.BTREE_FACTORY_ID] = (ConglomerateFactory) mfactory;
0207:
0208: // System.out.println("conglom_map[0] = " + conglom_map[0]);
0209: // System.out.println("conglom_map[1] = " + conglom_map[1]);
0210: }
0211:
0212: /***************************************************************************
0213: ** Abstract Methods of RAMAccessManager, interfaces that control locking
0214: ** level of the system.
0215: ****************************************************************************
0216: */
0217:
0218: /**
0219: * Return the locking level of the system.
0220: * <p>
0221: * This routine controls the lowest level of locking enabled for all locks
0222: * for all tables accessed through this accessmanager. The concrete
0223: * implementation may set this value always to table level locking for
0224: * a client configuration, or it may set it to row level locking for a
0225: * server configuration.
0226: * <p>
0227: * If TransactionController.MODE_RECORD is returned table may either be
0228: * locked at table or row locking depending on the type of access expected
0229: * (ie. level 3 will require table locking for heap scans.)
0230: *
0231: * @return TransactionController.MODE_TABLE if only table locking allowed,
0232: * else returns TransactionController.MODE_RECORD.
0233: *
0234: **/
0235: abstract protected int getSystemLockLevel();
0236:
0237: /**
0238: * Query property system to get the System lock level.
0239: * <p>
0240: * This routine will be called during boot after access has booted far
0241: * enough, to allow access to the property conglomerate. This routine
0242: * will call the property system and set the value to be returned by
0243: * getSystemLockLevel().
0244: * <p>
0245: *
0246: * @exception StandardException Standard exception policy.
0247: **/
0248: abstract protected void bootLookupSystemLockLevel(
0249: TransactionController tc) throws StandardException;
0250:
0251: /**************************************************************************
0252: * Routines to map to/from conglomid/containerid:
0253: **************************************************************************
0254: */
0255: private long conglom_nextid = 0;
0256:
0257: /**
0258: * Return next conglomid to try to add the container with.
0259: * <p>
0260: * The conglomerate number has 2 parts. The low 4 bits are used to
0261: * encode the factory which "owns" the conglomerate. The high 60 bits
0262: * are used as a normal unique id mechanism.
0263: * <p>
0264: * So for example if the next id to assign is 0x54 the following will
0265: * be the conglomid:
0266: * if a HEAP (factory 0) - 0x540
0267: * if a BTREE (factory 1) - 0x541
0268: *
0269: * And the next id assigned will be:
0270: * if a HEAP (factory 0) - 0x550
0271: * if a BTREE (factory 1) - 0x551
0272: *
0273: * @param factory_type factory id as gotten from getConglomerateFactoryId()
0274: *
0275: * @return The identifier to be used to open the conglomerate later.
0276: *
0277: * @exception StandardException Standard exception policy.
0278: **/
0279: protected long getNextConglomId(int factory_type)
0280: throws StandardException {
0281: long conglomid;
0282:
0283: if (SanityManager.DEBUG) {
0284: // current code depends on this range, if we ever need to expand the
0285: // range we can claim bits from the high order of the long.
0286:
0287: SanityManager.ASSERT(factory_type >= 0x00
0288: && factory_type <= 0x0f);
0289: }
0290:
0291: synchronized (conglom_cache) {
0292: if (conglom_nextid == 0) {
0293: // shift out the factory id and then add 1.
0294: conglom_nextid = (rawstore.getMaxContainerId() >> 4) + 1;
0295: }
0296:
0297: conglomid = conglom_nextid++;
0298: }
0299:
0300: // shift in the factory id and then return the conglomid.
0301:
0302: return ((conglomid << 4) | factory_type);
0303: }
0304:
0305: /**
0306: * Bump the conglomid.
0307: * <p>
0308: * For some reason we have found that the give conglomid already exists
0309: * in the directory so just bump the next conglomid to greater than this
0310: * one. The algorithm to store and retrieve the last conglomid is not
0311: * transactional as we don't want to pay the overhead for such an algorithm
0312: * on every ddl statement - so it is possible to "lose" an update to the
0313: * counter if we crash at an inopportune moment. In general the upper
0314: * level store code will just handle the error from addContainer which
0315: * says there already exists a conglom with that id, update the next
0316: * conglomid and then try again.
0317: * <p>
0318: *
0319: * @param conglomid The conglomid which already exists.
0320: *
0321: * @exception StandardException Standard exception policy.
0322: **/
0323: // currently not used, but this is one idea on how to handle
0324: // non-transactional update of the nextid field, just handle the error
0325: // if we try to create a conglom and find the container already exists.
0326: /*
0327: private void handleConglomidExists(
0328: long conglomid)
0329: throws StandardException
0330: {
0331: synchronized (conglom_cache)
0332: {
0333: conglom_nextid = ((conglomid >> 4) + 1);
0334: }
0335: }
0336: */
0337:
0338: /**
0339: * Given a conglomid, return the factory which "owns" it.
0340: * <p>
0341: * A simple lookup on the boot time built table which maps the low order
0342: * 4 bits into which factory owns the conglomerate.
0343: * <p>
0344: *
0345: * @param conglom_id The conglomerate id of the conglomerate to look up.
0346: *
0347: * @return The ConglomerateFactory which "owns" this conglomerate.
0348: *
0349: * @exception StandardException Standard exception policy.
0350: **/
0351: private ConglomerateFactory getFactoryFromConglomId(long conglom_id)
0352: throws StandardException {
0353: try {
0354: return (conglom_map[((int) (0x0f & conglom_id))]);
0355: } catch (java.lang.ArrayIndexOutOfBoundsException e) {
0356: // just in case language passes in a bad factory id.
0357: throw StandardException.newException(
0358: SQLState.STORE_CONGLOMERATE_DOES_NOT_EXIST,
0359: new Long(conglom_id));
0360: }
0361: }
0362:
0363: /**************************************************************************
0364: * Conglomerate Cache routines:
0365: **************************************************************************
0366: */
0367:
0368: /**
0369: * ACCESSMANAGER CONGLOMERATE CACHE -
0370: * <p>
0371: * Every conglomerate in the system is described by an object which
0372: * implements Conglomerate. This object basically contains the parameters
0373: * which describe the metadata about the conglomerate that store needs
0374: * to know - like types of columns, number of keys, number of columns, ...
0375: * <p>
0376: * It is up to each conglomerate to maintain it's own description, and
0377: * it's factory must be able to read this info from disk and return it
0378: * from the ConglomerateFactory.readConglomerate() interface.
0379: * <p>
0380: * This cache simply maintains an in memory copy of these conglomerate
0381: * objects, key'd by conglomerate id. By caching, this avoids the cost
0382: * of reading the conglomerate info from disk on each subsequent query
0383: * which accesses the conglomerate.
0384: * <p>
0385: * The interfaces and internal routines which deal with this cache are:
0386: * conglomCacheInit() - initializes the cache at boot time.
0387: *
0388: *
0389: *
0390: **/
0391:
0392: /**
0393: * Initialize the conglomerate cache.
0394: * <p>
0395: * Simply calls the cache manager to create the cache with some hard
0396: * coded defaults for size.
0397: * <p>
0398: * @exception StandardException Standard exception policy.
0399: **/
0400: private void conglomCacheInit() throws StandardException {
0401: // Get a cache factory to create the conglomerate cache.
0402: CacheFactory cf = (CacheFactory) Monitor
0403: .startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory);
0404:
0405: // Now create the conglomerate cache.
0406:
0407: conglom_cache = cf.newCacheManager(this ,
0408: AccessFactoryGlobals.CFG_CONGLOMDIR_CACHE, 200, 300);
0409:
0410: }
0411:
0412: /**
0413: * Find a conglomerate by conglomid in the cache.
0414: * <p>
0415: * Look for a conglomerate given a conglomid. If in cache return it,
0416: * otherwise fault in an entry by asking the owning factory to produce
0417: * an entry.
0418: * <p>
0419: *
0420: * @return The conglomerate object identified by "conglomid".
0421: *
0422: * @param conglomid The conglomerate id of the conglomerate to look up.
0423: *
0424: * @exception StandardException Standard exception policy.
0425: **/
0426: /* package */Conglomerate conglomCacheFind(
0427: TransactionManager xact_mgr, long conglomid)
0428: throws StandardException {
0429: Conglomerate conglom = null;
0430: Long conglomid_obj = new Long(conglomid);
0431:
0432: synchronized (conglom_cache) {
0433: CacheableConglomerate cache_entry = (CacheableConglomerate) conglom_cache
0434: .findCached(conglomid_obj);
0435:
0436: if (cache_entry != null) {
0437: conglom = cache_entry.getConglom();
0438: conglom_cache.release(cache_entry);
0439:
0440: // SanityManager.DEBUG_PRINT("find", "find hit : " + conglomid);
0441: } else {
0442: // SanityManager.DEBUG_PRINT("find", "find miss: " + conglomid);
0443:
0444: // If not in cache - ask the factory for it and insert it.
0445:
0446: conglom = getFactoryFromConglomId(conglomid)
0447: .readConglomerate(xact_mgr,
0448: new ContainerKey(0, conglomid));
0449:
0450: if (conglom != null) {
0451: // on cache miss, put the missing conglom in the cache.
0452: cache_entry = (CacheableConglomerate) this .conglom_cache
0453: .create(conglomid_obj, conglom);
0454: this .conglom_cache.release(cache_entry);
0455: }
0456: }
0457: }
0458:
0459: return (conglom);
0460: }
0461:
0462: /**
0463: * Invalide the current Conglomerate Cache.
0464: * <p>
0465: * Abort of certain operations will invalidate the contents of the
0466: * cache. Longer term we could just invalidate those entries, but
0467: * for now just invalidate the whole cache.
0468: * <p>
0469: *
0470: * @exception StandardException Standard exception policy.
0471: **/
0472: /* package */protected void conglomCacheInvalidate()
0473: throws StandardException {
0474: synchronized (conglom_cache) {
0475: conglom_cache.ageOut();
0476: }
0477:
0478: return;
0479: }
0480:
0481: /**
0482: * Update a conglomerate directory entry.
0483: * <p>
0484: * Update the Conglom column of the Conglomerate Directory. The
0485: * Conglomerate with id "conglomid" is replaced by "new_conglom".
0486: * <p>
0487: *
0488: * @param conglomid The conglomid of conglomerate to replace.
0489: * @param new_conglom The new Conglom to update the conglom column to.
0490: *
0491: * @exception StandardException Standard exception policy.
0492: **/
0493: /* package */void conglomCacheUpdateEntry(long conglomid,
0494: Conglomerate new_conglom) throws StandardException {
0495: Long conglomid_obj = new Long(conglomid);
0496:
0497: synchronized (conglom_cache) {
0498: // remove the current entry
0499: CacheableConglomerate conglom_entry = (CacheableConglomerate) conglom_cache
0500: .findCached(conglomid_obj);
0501:
0502: if (conglom_entry != null)
0503: conglom_cache.remove(conglom_entry);
0504:
0505: // insert the updated entry.
0506: conglom_entry = (CacheableConglomerate) conglom_cache
0507: .create(conglomid_obj, new_conglom);
0508: conglom_cache.release(conglom_entry);
0509: }
0510:
0511: return;
0512: }
0513:
0514: /**
0515: * Add a newly created conglomerate to the cache.
0516: * <p>
0517: *
0518: * @param conglomid The conglomid of conglomerate to replace.
0519: * @param conglom The Conglom to add.
0520: *
0521: * @exception StandardException Standard exception policy.
0522: **/
0523: /* package */void conglomCacheAddEntry(long conglomid,
0524: Conglomerate conglom) throws StandardException {
0525: synchronized (conglom_cache) {
0526: // insert the updated entry.
0527: CacheableConglomerate conglom_entry = (CacheableConglomerate) conglom_cache
0528: .create(new Long(conglomid), conglom);
0529: conglom_cache.release(conglom_entry);
0530: }
0531:
0532: return;
0533: }
0534:
0535: /**
0536: * Remove an entry from the cache.
0537: * <p>
0538: *
0539: * @param conglomid The conglomid of conglomerate to replace.
0540: *
0541: * @exception StandardException Standard exception policy.
0542: **/
0543: /* package */void conglomCacheRemoveEntry(long conglomid)
0544: throws StandardException {
0545: synchronized (conglom_cache) {
0546: CacheableConglomerate conglom_entry = (CacheableConglomerate) conglom_cache
0547: .findCached(new Long(conglomid));
0548:
0549: if (conglom_entry != null)
0550: conglom_cache.remove(conglom_entry);
0551: }
0552:
0553: return;
0554: }
0555:
0556: /**************************************************************************
0557: * Public Methods implementing AccessFactory Interface:
0558: **************************************************************************
0559: */
0560:
0561: /**
0562: Database creation finished. Tell RawStore.
0563: @exception StandardException cloudscape standard error policy
0564: */
0565: public void createFinished() throws StandardException {
0566: rawstore.createFinished();
0567: }
0568:
0569: /**
0570: Find an access method that implements a format type.
0571: @see AccessFactory#findMethodFactoryByFormat
0572: **/
0573: public MethodFactory findMethodFactoryByFormat(UUID format) {
0574: MethodFactory factory;
0575:
0576: // See if there's an access method that supports the desired
0577: // format type as its primary format type.
0578: factory = (MethodFactory) formathash.get(format);
0579: if (factory != null)
0580: return factory;
0581:
0582: // No primary format. See if one of the access methods
0583: // supports it as a secondary format.
0584: Enumeration e = formathash.elements();
0585: while (e.hasMoreElements()) {
0586: factory = (MethodFactory) e.nextElement();
0587: if (factory.supportsFormat(format))
0588: return factory;
0589: }
0590:
0591: // No such implementation.
0592: return null;
0593: }
0594:
0595: /**
0596: Find an access method that implements an implementation type.
0597: @see AccessFactory#findMethodFactoryByImpl
0598: **/
0599: public MethodFactory findMethodFactoryByImpl(String impltype)
0600: throws StandardException {
0601: // See if there's an access method that supports the desired
0602: // implementation type as its primary implementation type.
0603: MethodFactory factory = (MethodFactory) implhash.get(impltype);
0604: if (factory != null)
0605: return factory;
0606:
0607: // No primary implementation. See if one of the access methods
0608: // supports the implementation type as a secondary.
0609: Enumeration e = implhash.elements();
0610: while (e.hasMoreElements()) {
0611: factory = (MethodFactory) e.nextElement();
0612: if (factory.supportsImplementation(impltype))
0613: return factory;
0614: }
0615: factory = null;
0616:
0617: // try and load an implementation. a new properties object needs
0618: // to be created to hold the conglomerate type property, since
0619: // that value is specific to the conglomerate we want to boot, not
0620: // to the service as a whole
0621: Properties conglomProperties = new Properties(serviceProperties);
0622: conglomProperties.put(AccessFactoryGlobals.CONGLOM_PROP,
0623: impltype);
0624:
0625: try {
0626: factory = (MethodFactory) Monitor.bootServiceModule(false,
0627: this , MethodFactory.MODULE, impltype,
0628: conglomProperties);
0629: } catch (StandardException se) {
0630: if (!se.getMessageId().equals(
0631: SQLState.SERVICE_MISSING_IMPLEMENTATION))
0632: throw se;
0633: }
0634:
0635: conglomProperties = null;
0636:
0637: if (factory != null) {
0638: registerAccessMethod(factory);
0639: return factory;
0640: }
0641:
0642: // No such implementation.
0643: return null;
0644: }
0645:
0646: public LockFactory getLockFactory() {
0647: return rawstore.getLockFactory();
0648: }
0649:
0650: public TransactionController getTransaction(ContextManager cm)
0651: throws StandardException {
0652: return getAndNameTransaction(cm,
0653: AccessFactoryGlobals.USER_TRANS_NAME);
0654: }
0655:
0656: public TransactionController getAndNameTransaction(
0657: ContextManager cm, String transName)
0658: throws StandardException {
0659: if (cm == null)
0660: return null; // XXX (nat) should throw exception
0661:
0662: // See if there's already a transaction context.
0663: RAMTransactionContext rtc = (RAMTransactionContext) cm
0664: .getContext(AccessFactoryGlobals.RAMXACT_CONTEXT_ID);
0665:
0666: if (rtc == null) {
0667: // No transaction context. Create or find a raw store transaction,
0668: // make a context for it, and push the context. Note this puts the
0669: // raw store transaction context above the access context, which is
0670: // required for error handling assumptions to be correct.
0671: Transaction rawtran = rawstore.findUserTransaction(cm,
0672: transName);
0673: RAMTransaction rt = new RAMTransaction(this , rawtran, null);
0674:
0675: rtc = new RAMTransactionContext(cm,
0676: AccessFactoryGlobals.RAMXACT_CONTEXT_ID, rt, false /* abortAll */);
0677:
0678: TransactionController tc = rtc.getTransaction();
0679:
0680: if (xactProperties != null) {
0681: rawtran.setup(tc);
0682: tc.commit();
0683: }
0684:
0685: rawtran
0686: .setDefaultLockingPolicy(system_default_locking_policy);
0687:
0688: tc.commit();
0689:
0690: return tc;
0691: }
0692: return rtc.getTransaction();
0693: }
0694:
0695: /**
0696: * Start a global transaction.
0697: * <p>
0698: * Get a transaction controller with which to manipulate data within
0699: * the access manager. Implicitly creates an access context.
0700: * <p>
0701: * Must only be called if no other transaction context exists in the
0702: * current context manager. If another transaction exists in the context
0703: * an exception will be thrown.
0704: * <p>
0705: * The (format_id, global_id, branch_id) triplet is meant to come exactly
0706: * from a javax.transaction.xa.Xid. We don't use Xid so that the system
0707: * can be delivered on a non-1.2 vm system and not require the javax classes
0708: * in the path.
0709: *
0710: * @param cm The context manager for the current context.
0711: * @param format_id the format id part of the Xid - ie. Xid.getFormatId().
0712: * @param global_id the global transaction identifier part of XID - ie.
0713: * Xid.getGlobalTransactionId().
0714: * @param branch_id The branch qualifier of the Xid - ie.
0715: * Xid.getBranchQaulifier()
0716: *
0717: * @exception StandardException Standard exception policy.
0718: * @see TransactionController
0719: **/
0720: public/* XATransactionController */Object startXATransaction(
0721: ContextManager cm, int format_id, byte[] global_id,
0722: byte[] branch_id) throws StandardException {
0723: RAMTransaction xa_tc = null;
0724:
0725: if (SanityManager.DEBUG) {
0726: SanityManager.ASSERT(global_id != null);
0727: SanityManager.ASSERT(branch_id != null);
0728: }
0729:
0730: if (cm == null)
0731: return null; // XXX (nat) should throw exception
0732:
0733: // See if there's already a transaction context.
0734: RAMTransactionContext rtc = (RAMTransactionContext) cm
0735: .getContext(AccessFactoryGlobals.RAMXACT_CONTEXT_ID);
0736:
0737: if (rtc == null) {
0738: // No transaction context. Create or find a raw store transaction,
0739: // make a context for it, and push the context. Note this puts the
0740: // raw store transaction context above the access context, which is
0741: // required for error handling assumptions to be correct.
0742: Transaction rawtran = rawstore.startGlobalTransaction(cm,
0743: format_id, global_id, branch_id);
0744:
0745: xa_tc = new RAMTransaction(this , rawtran, null);
0746:
0747: rtc = new RAMTransactionContext(cm,
0748: AccessFactoryGlobals.RAMXACT_CONTEXT_ID, xa_tc,
0749: false /* abortAll */);
0750:
0751: // RESOLVE - an XA transaction can only commit once so, if we
0752: // acquire readlocks.
0753:
0754: if (xactProperties != null) {
0755: rawtran.setup(xa_tc);
0756:
0757: // HACK - special support has been added to the commitNoSync
0758: // of a global xact, to allow committing of read only xact,
0759: // which will allow subsequent activity on the xact keeping
0760: // the same global transaction id.
0761: xa_tc
0762: .commitNoSync(TransactionController.RELEASE_LOCKS
0763: | TransactionController.READONLY_TRANSACTION_INITIALIZATION);
0764: }
0765:
0766: rawtran
0767: .setDefaultLockingPolicy(system_default_locking_policy);
0768:
0769: // HACK - special support has been added to the commitNoSync
0770: // of a global xact, to allow committing of read only xact,
0771: // which will allow subsequent activity on the xact keeping
0772: // the same global transaction id.
0773: xa_tc
0774: .commitNoSync(TransactionController.RELEASE_LOCKS
0775: | TransactionController.READONLY_TRANSACTION_INITIALIZATION);
0776: } else {
0777: // throw an error.
0778: if (SanityManager.DEBUG)
0779: SanityManager
0780: .THROWASSERT("RAMTransactionContext found on stack.");
0781: }
0782:
0783: return (xa_tc);
0784: }
0785:
0786: /**
0787: * Return the XAResourceManager associated with this AccessFactory.
0788: * <p>
0789: * Returns an object which can be used to implement the "offline"
0790: * 2 phase commit interaction between the accessfactory and outstanding
0791: * transaction managers taking care of in-doubt transactions.
0792: *
0793: * @return The XAResourceManager associated with this accessfactory.
0794: *
0795: **/
0796: public/* XAResourceManager */Object getXAResourceManager()
0797: throws StandardException {
0798: return (rawstore.getXAResourceManager());
0799: }
0800:
0801: public void registerAccessMethod(MethodFactory factory) {
0802: // Put the access method's primary implementation type in
0803: // a hash table so we can find it quickly.
0804: implhash.put(factory.primaryImplementationType(), factory);
0805:
0806: // Put the access method's primary format in a hash table
0807: // so we can find it quickly.
0808: formathash.put(factory.primaryFormat(), factory);
0809: }
0810:
0811: public boolean isReadOnly() {
0812: return rawstore.isReadOnly();
0813: }
0814:
0815: private void addPropertySetNotification(PropertySetCallback who,
0816: TransactionController tc) {
0817:
0818: pf.addPropertySetNotification(who);
0819:
0820: // set up the initial values by calling the validate and apply methods.
0821: // the map methods are not called as they will have been called
0822: // at runtime when the user set the property.
0823: Dictionary d = new Hashtable();
0824: try {
0825: xactProperties.getProperties(tc, d, false/*!stringsOnly*/,
0826: false/*!defaultsOnly*/);
0827: } catch (StandardException se) {
0828: return;
0829: }
0830:
0831: boolean dbOnly = PropertyUtil.isDBOnly(d);
0832:
0833: who.init(dbOnly, d);
0834: }
0835:
0836: public TransactionInfo[] getTransactionInfo() {
0837: return rawstore.getTransactionInfo();
0838: }
0839:
0840: public void freeze() throws StandardException {
0841: rawstore.freeze();
0842: }
0843:
0844: public void unfreeze() throws StandardException {
0845: rawstore.unfreeze();
0846: }
0847:
0848: public void backup(String backupDir, boolean wait)
0849: throws StandardException {
0850: rawstore.backup(backupDir, wait);
0851: }
0852:
0853: public void backupAndEnableLogArchiveMode(String backupDir,
0854: boolean deleteOnlineArchivedLogFiles, boolean wait)
0855: throws StandardException {
0856: rawstore.backupAndEnableLogArchiveMode(backupDir,
0857: deleteOnlineArchivedLogFiles, wait);
0858: }
0859:
0860: public void disableLogArchiveMode(
0861: boolean deleteOnlineArchivedLogFiles)
0862: throws StandardException {
0863: rawstore.disableLogArchiveMode(deleteOnlineArchivedLogFiles);
0864: }
0865:
0866: public void checkpoint() throws StandardException {
0867: rawstore.checkpoint();
0868: }
0869:
0870: public void waitForPostCommitToFinishWork() {
0871: rawstore.getDaemon().waitUntilQueueIsEmpty();
0872: }
0873:
0874: /**************************************************************************
0875: * Public Methods implementing ModuleControl Interface:
0876: **************************************************************************
0877: */
0878: public void boot(boolean create, Properties startParams)
0879: throws StandardException {
0880: this .serviceProperties = startParams;
0881:
0882: boot_load_conglom_map();
0883:
0884: if (create) {
0885: // if we are creating the db, then just start the conglomid's at
0886: // 1, and proceed from there. If not create, we delay
0887: // initialization of this until the first ddl which needs a new
0888: // id.
0889: conglom_nextid = 1;
0890: }
0891:
0892: // Access depends on a Raw Store implementations. Load it.
0893: //
0894: rawstore = (RawStoreFactory) Monitor.bootServiceModule(create,
0895: this , RawStoreFactory.MODULE, serviceProperties);
0896:
0897: // Note: we also boot this module here since we may start cloudscape
0898: // system from store access layer, as some of the unit test case,
0899: // not from JDBC layer.(See
0900: // /protocol/Database/Storage/Access/Interface/T_AccessFactory.java)
0901: // If this module has already been booted by the JDBC layer, this will
0902: // have no effect at all.
0903: Monitor.bootServiceModule(create, this ,
0904: org.apache.derby.iapi.reference.Module.PropertyFactory,
0905: startParams);
0906:
0907: // Create the in-memory conglomerate directory
0908:
0909: conglomCacheInit();
0910:
0911: // Read in the conglomerate directory from the conglom conglom
0912: // Create the conglom conglom from within a separate system xact
0913: RAMTransaction tc = (RAMTransaction) getAndNameTransaction(
0914: ContextService.getFactory().getCurrentContextManager(),
0915: AccessFactoryGlobals.USER_TRANS_NAME);
0916:
0917: // looking up lock_mode is dependant on access booting, but
0918: // some boot routines need lock_mode and
0919: // system_default_locking_policy, so during boot do table level
0920: // locking and then look up the "right" locking level.
0921:
0922: int lock_mode = LockingPolicy.MODE_CONTAINER;
0923:
0924: system_default_locking_policy = tc.getRawStoreXact()
0925: .newLockingPolicy(lock_mode,
0926: TransactionController.ISOLATION_SERIALIZABLE,
0927: true);
0928:
0929: // RESOLVE - code reduction - get rid of this table, and somehow
0930: // combine it with the raw store one.
0931:
0932: table_level_policy = new LockingPolicy[6];
0933:
0934: table_level_policy[TransactionController.ISOLATION_NOLOCK] = tc
0935: .getRawStoreXact().newLockingPolicy(
0936: LockingPolicy.MODE_CONTAINER,
0937: TransactionController.ISOLATION_NOLOCK, true);
0938:
0939: table_level_policy[TransactionController.ISOLATION_READ_UNCOMMITTED] = tc
0940: .getRawStoreXact()
0941: .newLockingPolicy(
0942: LockingPolicy.MODE_CONTAINER,
0943: TransactionController.ISOLATION_READ_UNCOMMITTED,
0944: true);
0945:
0946: table_level_policy[TransactionController.ISOLATION_READ_COMMITTED] = tc
0947: .getRawStoreXact().newLockingPolicy(
0948: LockingPolicy.MODE_CONTAINER,
0949: TransactionController.ISOLATION_READ_COMMITTED,
0950: true);
0951:
0952: table_level_policy[TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] = tc
0953: .getRawStoreXact()
0954: .newLockingPolicy(
0955: LockingPolicy.MODE_CONTAINER,
0956: TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,
0957: true);
0958:
0959: table_level_policy[TransactionController.ISOLATION_REPEATABLE_READ] = tc
0960: .getRawStoreXact()
0961: .newLockingPolicy(
0962: LockingPolicy.MODE_CONTAINER,
0963: TransactionController.ISOLATION_REPEATABLE_READ,
0964: true);
0965:
0966: table_level_policy[TransactionController.ISOLATION_SERIALIZABLE] = tc
0967: .getRawStoreXact().newLockingPolicy(
0968: LockingPolicy.MODE_CONTAINER,
0969: TransactionController.ISOLATION_SERIALIZABLE,
0970: true);
0971:
0972: record_level_policy = new LockingPolicy[6];
0973:
0974: record_level_policy[TransactionController.ISOLATION_NOLOCK] = tc
0975: .getRawStoreXact().newLockingPolicy(
0976: LockingPolicy.MODE_RECORD,
0977: TransactionController.ISOLATION_NOLOCK, true);
0978:
0979: record_level_policy[TransactionController.ISOLATION_READ_UNCOMMITTED] = tc
0980: .getRawStoreXact()
0981: .newLockingPolicy(
0982: LockingPolicy.MODE_RECORD,
0983: TransactionController.ISOLATION_READ_UNCOMMITTED,
0984: true);
0985:
0986: record_level_policy[TransactionController.ISOLATION_READ_COMMITTED] = tc
0987: .getRawStoreXact().newLockingPolicy(
0988: LockingPolicy.MODE_RECORD,
0989: TransactionController.ISOLATION_READ_COMMITTED,
0990: true);
0991:
0992: record_level_policy[TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] = tc
0993: .getRawStoreXact()
0994: .newLockingPolicy(
0995: LockingPolicy.MODE_RECORD,
0996: TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,
0997: true);
0998:
0999: record_level_policy[TransactionController.ISOLATION_REPEATABLE_READ] = tc
1000: .getRawStoreXact()
1001: .newLockingPolicy(
1002: LockingPolicy.MODE_RECORD,
1003: TransactionController.ISOLATION_REPEATABLE_READ,
1004: true);
1005:
1006: record_level_policy[TransactionController.ISOLATION_SERIALIZABLE] = tc
1007: .getRawStoreXact().newLockingPolicy(
1008: LockingPolicy.MODE_RECORD,
1009: TransactionController.ISOLATION_SERIALIZABLE,
1010: true);
1011:
1012: if (SanityManager.DEBUG) {
1013: for (int i = 0; i < TransactionController.ISOLATION_SERIALIZABLE; i++) {
1014: SanityManager.ASSERT(table_level_policy[i] != null,
1015: "table_level_policy[" + i + "] is null");
1016: SanityManager.ASSERT(record_level_policy[i] != null,
1017: "record_level_policy[" + i + "] is null");
1018: }
1019: }
1020:
1021: tc.commit();
1022:
1023: // set up the property validation
1024: pf = (PropertyFactory) Monitor.findServiceModule(this ,
1025: org.apache.derby.iapi.reference.Module.PropertyFactory);
1026:
1027: // set up the transaction properties. On J9, over NFS, runing on a
1028: // power PC coprossor, the directories were created fine, but create
1029: // db would fail when trying to create this first file in seg0.
1030: xactProperties = new PropertyConglomerate(tc, create,
1031: startParams, pf);
1032:
1033: // see if there is any properties that raw store needs to know
1034: // about
1035: rawstore.getRawStoreProperties(tc);
1036:
1037: // now that access and raw store are booted, do the property lookup
1038: // which may do conglomerate access.
1039: bootLookupSystemLockLevel(tc);
1040:
1041: lock_mode = (getSystemLockLevel() == TransactionController.MODE_TABLE ? LockingPolicy.MODE_CONTAINER
1042: : LockingPolicy.MODE_RECORD);
1043:
1044: system_default_locking_policy = tc.getRawStoreXact()
1045: .newLockingPolicy(lock_mode,
1046: TransactionController.ISOLATION_SERIALIZABLE,
1047: true);
1048:
1049: // set up the callbacl for the lock manager with initialization
1050: addPropertySetNotification(getLockFactory(), tc);
1051:
1052: // make sure user cannot change these properties
1053: addPropertySetNotification(this , tc);
1054:
1055: tc.commit();
1056:
1057: tc.destroy();
1058: tc = null;
1059:
1060: if (SanityManager.DEBUG) {
1061: // RESOLVE - (mikem) currently these constants need to be the
1062: // same, but for modularity reasons there are 2 sets. Probably
1063: // should only be one set. For now just make sure they are the
1064: // same value.
1065: SanityManager
1066: .ASSERT(TransactionController.OPENMODE_USE_UPDATE_LOCKS == ContainerHandle.MODE_USE_UPDATE_LOCKS);
1067: SanityManager
1068: .ASSERT(TransactionController.OPENMODE_SECONDARY_LOCKED == ContainerHandle.MODE_SECONDARY_LOCKED);
1069: SanityManager
1070: .ASSERT(TransactionController.OPENMODE_BASEROW_INSERT_LOCKED == ContainerHandle.MODE_BASEROW_INSERT_LOCKED);
1071: SanityManager
1072: .ASSERT(TransactionController.OPENMODE_FORUPDATE == ContainerHandle.MODE_FORUPDATE);
1073: SanityManager
1074: .ASSERT(TransactionController.OPENMODE_FOR_LOCK_ONLY == ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY);
1075: }
1076: }
1077:
1078: public void stop() {
1079: }
1080:
1081: /* Methods of the PropertySetCallback interface */
1082:
1083: // This interface is implemented to ensure the user cannot change the
1084: // encryption provider or algorithm.
1085: public void init(boolean dbOnly, Dictionary p) {
1086: }
1087:
1088: public boolean validate(String key, Serializable value, Dictionary p)
1089: throws StandardException {
1090: if (key.equals(Attribute.CRYPTO_ALGORITHM)) {
1091: throw StandardException
1092: .newException(SQLState.ENCRYPTION_NOCHANGE_ALGORITHM);
1093: }
1094: if (key.equals(Attribute.CRYPTO_PROVIDER)) {
1095: throw StandardException
1096: .newException(SQLState.ENCRYPTION_NOCHANGE_PROVIDER);
1097: }
1098: return true;
1099: }
1100:
1101: public Serviceable apply(String key, Serializable value,
1102: Dictionary p) throws StandardException {
1103: return null;
1104: }
1105:
1106: public Serializable map(String key, Serializable value, Dictionary p)
1107: throws StandardException {
1108: return null;
1109: }
1110:
1111: // ///////////////////////////////////////////////////////////////
1112:
1113: /*
1114: ** CacheableFactory interface
1115: */
1116:
1117: public Cacheable newCacheable(CacheManager cm) {
1118: return new CacheableConglomerate();
1119: }
1120:
1121: }
|