0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.depend.BasicDependencyManager
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.sql.depend;
0023:
0024: import org.apache.derby.catalog.Dependable;
0025: import org.apache.derby.catalog.DependableFinder;
0026:
0027: import org.apache.derby.iapi.services.context.ContextManager;
0028: import org.apache.derby.iapi.services.context.ContextService;
0029:
0030: import org.apache.derby.iapi.services.monitor.Monitor;
0031:
0032: import org.apache.derby.iapi.services.sanity.SanityManager;
0033:
0034: import org.apache.derby.iapi.sql.compile.CompilerContext;
0035: import org.apache.derby.iapi.sql.compile.Parser;
0036: import org.apache.derby.impl.sql.compile.CreateViewNode;
0037:
0038: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0039: import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
0040: import org.apache.derby.iapi.sql.conn.StatementContext;
0041:
0042: import org.apache.derby.iapi.sql.depend.DependencyManager;
0043: import org.apache.derby.iapi.sql.depend.Dependency;
0044: import org.apache.derby.iapi.sql.depend.Dependent;
0045: import org.apache.derby.iapi.sql.depend.Provider;
0046: import org.apache.derby.iapi.sql.depend.ProviderInfo;
0047: import org.apache.derby.iapi.sql.depend.ProviderList;
0048:
0049: import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
0050: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0051: import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
0052: import org.apache.derby.iapi.sql.dictionary.DependencyDescriptor;
0053: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0054: import org.apache.derby.iapi.sql.dictionary.ViewDescriptor;
0055: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
0056:
0057: import org.apache.derby.impl.sql.catalog.DDColumnDependableFinder;
0058: import org.apache.derby.iapi.store.access.TransactionController;
0059:
0060: import org.apache.derby.catalog.UUID;
0061: import org.apache.derby.iapi.reference.SQLState;
0062: import org.apache.derby.iapi.services.io.FormatableBitSet;
0063:
0064: import org.apache.derby.iapi.reference.MessageId;
0065:
0066: import org.apache.derby.iapi.error.StandardException;
0067:
0068: import java.util.Hashtable;
0069: import java.util.Enumeration;
0070: import java.util.ListIterator;
0071: import java.util.List;
0072:
0073: /**
0074: The dependency manager tracks needs that dependents have of providers.
0075: */
0076:
0077: public class BasicDependencyManager implements DependencyManager {
0078:
0079: //
0080: // DependencyManager interface
0081: //
0082:
0083: /**
0084: adds a dependency from the dependent on the provider.
0085: This will be considered to be the default type of
0086: dependency, when dependency types show up.
0087: <p>
0088: Implementations of addDependency should be fast --
0089: performing alot of extra actions to add a dependency would
0090: be a detriment.
0091:
0092: @param d the dependent
0093: @param p the provider
0094:
0095: @exception StandardException thrown if something goes wrong
0096: */
0097: public void addDependency(Dependent d, Provider p, ContextManager cm)
0098: throws StandardException {
0099: addDependency(d, p, cm, null);
0100: }
0101:
0102: private void addDependency(Dependent d, Provider p,
0103: ContextManager cm, TransactionController tc)
0104: throws StandardException {
0105:
0106: synchronized (this ) {
0107: Dependency dy = new BasicDependency(d, p);
0108:
0109: /* Dependencies are either in-memory or stored, but not both */
0110: if (!d.isPersistent() || !p.isPersistent()) {
0111: /* Duplicate dependencies are not added to the lists.
0112: * If we find that the dependency we are trying to add in
0113: * one list is a duplicate, then it should be a duplicate in the
0114: * other list.
0115: */
0116: boolean addedToDeps = false;
0117: boolean addedToProvs = false;
0118:
0119: addedToDeps = addDependencyToTable(dependents, d
0120: .getObjectID(), dy);
0121: if (addedToDeps) {
0122: addedToProvs = addDependencyToTable(providers, p
0123: .getObjectID(), dy);
0124: } else if (SanityManager.DEBUG) {
0125: addedToProvs = addDependencyToTable(providers, p
0126: .getObjectID(), dy);
0127: }
0128:
0129: /* Dependency should have been added to both or neither */
0130: if (SanityManager.DEBUG) {
0131: if (addedToDeps != addedToProvs) {
0132: SanityManager.THROWASSERT("addedToDeps ("
0133: + addedToDeps + ") and addedToProvs ("
0134: + addedToProvs
0135: + ") are expected to agree");
0136: }
0137: }
0138:
0139: /* Add the dependency to the StatementContext, so that
0140: * it can be cleared on a pre-execution error.
0141: */
0142: StatementContext sc = (StatementContext) cm
0143: .getContext(org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT);
0144: sc.addDependency(dy);
0145: } else {
0146: /* Add a stored dependency */
0147: LanguageConnectionContext lcc = getLanguageConnectionContext(cm);
0148: DataDictionary dd = getDataDictionary();
0149: DependencyDescriptor dependencyDescriptor;
0150: boolean wait = (tc == null);
0151:
0152: dependencyDescriptor = new DependencyDescriptor(d, p);
0153:
0154: /* We can finally call the DataDictionary to store the dependency */
0155: dd.addDescriptor(dependencyDescriptor, null,
0156: DataDictionary.SYSDEPENDS_CATALOG_NUM, true,
0157: ((wait) ? lcc.getTransactionExecute() : tc),
0158: wait);
0159: }
0160: }
0161: }
0162:
0163: /**
0164: drops a single dependency
0165:
0166: @param d the dependent
0167: @param p the provider
0168:
0169: @exception StandardException thrown if something goes wrong
0170: */
0171: private void dropDependency(LanguageConnectionContext lcc,
0172: Dependent d, Provider p) throws StandardException {
0173: if (SanityManager.DEBUG) {
0174: // right now, this routine isn't called for in-memory dependencies
0175: if (!d.isPersistent() || !p.isPersistent()) {
0176: SanityManager.NOTREACHED();
0177: }
0178: }
0179:
0180: DataDictionary dd = getDataDictionary();
0181:
0182: DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(
0183: d, p);
0184:
0185: dd.dropStoredDependency(dependencyDescriptor, lcc
0186: .getTransactionExecute());
0187: }
0188:
0189: /**
0190: mark all dependencies on the named provider as invalid.
0191: When invalidation types show up, this will use the default
0192: invalidation type. The dependencies will still exist once
0193: they are marked invalid; clearDependencies should be used
0194: to remove dependencies that a dependent has or provider gives.
0195: <p>
0196: Implementations of this can take a little time, but are not
0197: really expected to recompile things against any changes
0198: made to the provider that caused the invalidation. The
0199: dependency system makes no guarantees about the state of
0200: the provider -- implementations can call this before or
0201: after actually changing the provider to its new state.
0202: <p>
0203: Implementations should throw StandardException
0204: if the invalidation should be disallowed.
0205:
0206: @param p the provider
0207: @param action The action causing the invalidate
0208:
0209: @exception StandardException thrown if unable to make it invalid
0210: */
0211: public void invalidateFor(Provider p, int action,
0212: LanguageConnectionContext lcc) throws StandardException {
0213: /*
0214: ** Non-persistent dependencies are stored in memory, and need to
0215: ** use "synchronized" to ensure their lists don't change while
0216: ** the invalidation is taking place. Persistent dependencies are
0217: ** stored in the data dictionary, and we should *not* do anything
0218: ** transactional (like reading from a system table) from within
0219: ** a synchronized method, as it could cause deadlock.
0220: **
0221: ** Presumably, the transactional locking in the data dictionary
0222: ** is enough to protect us, so that we don't have to put any
0223: ** synchronization in the DependencyManager.
0224: */
0225: if (p.isPersistent())
0226: coreInvalidateFor(p, action, lcc);
0227: else {
0228: synchronized (this ) {
0229: coreInvalidateFor(p, action, lcc);
0230: }
0231: }
0232: }
0233:
0234: /**
0235: * A version of invalidateFor that does not provide synchronization among
0236: * invalidators. If parameter "forSync" is true, it also provides
0237: * synchronization on the dependents. Currently, this means synchronizing
0238: * on the prepared statements, which might be being executed on other
0239: * threads.
0240: * @param p provider
0241: * @param action The action causing the invalidate
0242: * @param lcc Language connection context
0243: *
0244: * @exception StandardException Thrown on error.
0245: */
0246: private void coreInvalidateFor(Provider p, int action,
0247: LanguageConnectionContext lcc) throws StandardException {
0248: List list = getDependents(p);
0249: if (list == null) {
0250: return;
0251: }
0252:
0253: // affectedCols is passed in from table descriptor provider to indicate
0254: // which columns it cares; subsetCols is affectedCols' intersection
0255: // with column bit map found in the provider of SYSDEPENDS line to
0256: // find out which columns really matter. If SYSDEPENDS line's
0257: // dependent is view (or maybe others), provider is table, yet it
0258: // doesn't have column bit map because the view was created in a
0259: // previous version of server which doesn't support column dependency,
0260: // and we really want it to have (such as in drop column), in any case
0261: // if we passed in table descriptor to this function with a bit map,
0262: // we really need this, we generate the bitmaps on the fly and update
0263: // SYSDEPENDS
0264:
0265: FormatableBitSet affectedCols = null, subsetCols = null;
0266: if (p instanceof TableDescriptor) {
0267: affectedCols = ((TableDescriptor) p)
0268: .getReferencedColumnMap();
0269: if (affectedCols != null)
0270: subsetCols = new FormatableBitSet(affectedCols
0271: .getLength());
0272: }
0273:
0274: {
0275: StandardException noInvalidate = null;
0276: // We cannot use an iterator here as the invalidations can remove
0277: // entries from this list.
0278: for (int ei = list.size() - 1; ei >= 0; ei--) {
0279: if (ei >= list.size())
0280: continue;
0281: Dependency dependency = (Dependency) list.get(ei);
0282:
0283: Dependent dep = dependency.getDependent();
0284:
0285: if (affectedCols != null) {
0286: TableDescriptor td = (TableDescriptor) dependency
0287: .getProvider();
0288: FormatableBitSet providingCols = td
0289: .getReferencedColumnMap();
0290: if (providingCols == null) {
0291: if (dep instanceof ViewDescriptor) {
0292: ViewDescriptor vd = (ViewDescriptor) dep;
0293: DataDictionary dd = getDataDictionary();
0294: SchemaDescriptor compSchema;
0295: compSchema = dd.getSchemaDescriptor(vd
0296: .getCompSchemaId(), null);
0297: CompilerContext newCC = lcc
0298: .pushCompilerContext(compSchema);
0299: Parser pa = newCC.getParser();
0300: LanguageConnectionFactory lcf = lcc
0301: .getLanguageConnectionFactory();
0302:
0303: // Since this is always nested inside another SQL
0304: // statement, so topLevel flag should be false
0305: CreateViewNode cvn = (CreateViewNode) pa
0306: .parseStatement(vd.getViewText());
0307:
0308: // need a current dependent for bind
0309: newCC.setCurrentDependent(dep);
0310: cvn = (CreateViewNode) cvn.bind();
0311: ProviderInfo[] providerInfos = cvn
0312: .getProviderInfo();
0313: lcc.popCompilerContext(newCC);
0314:
0315: boolean interferent = false;
0316: for (int i = 0; i < providerInfos.length; i++) {
0317: Provider provider = null;
0318: try {
0319: provider = (Provider) providerInfos[i]
0320: .getDependableFinder()
0321: .getDependable(
0322: providerInfos[i]
0323: .getObjectId());
0324: } catch (java.sql.SQLException te) {
0325: if (SanityManager.DEBUG) {
0326: SanityManager
0327: .THROWASSERT("unexpected java.sql.SQLException - "
0328: + te);
0329: }
0330: }
0331: if (provider instanceof TableDescriptor) {
0332: TableDescriptor tab = (TableDescriptor) provider;
0333: FormatableBitSet colMap = tab
0334: .getReferencedColumnMap();
0335: if (colMap == null)
0336: continue;
0337: // if later on an error is raised such as in
0338: // case of interference, this dependency line
0339: // upgrade will not happen due to rollback
0340: tab.setReferencedColumnMap(null);
0341: dropDependency(lcc, vd, tab);
0342: tab.setReferencedColumnMap(colMap);
0343: addDependency(vd, tab, lcc
0344: .getContextManager());
0345:
0346: if (tab.getObjectID().equals(
0347: td.getObjectID())) {
0348: System
0349: .arraycopy(
0350: affectedCols
0351: .getByteArray(),
0352: 0,
0353: subsetCols
0354: .getByteArray(),
0355: 0,
0356: affectedCols
0357: .getLengthInBytes());
0358: subsetCols.and(colMap);
0359: if (subsetCols.anySetBit() != -1) {
0360: interferent = true;
0361: ((TableDescriptor) p)
0362: .setReferencedColumnMap(subsetCols);
0363: }
0364: }
0365: } // if provider instanceof TableDescriptor
0366: } // for providerInfos
0367: if (!interferent)
0368: continue;
0369: } // if dep instanceof ViewDescriptor
0370: else
0371: ((TableDescriptor) p)
0372: .setReferencedColumnMap(null);
0373: } // if providingCols == null
0374: else {
0375: System.arraycopy(affectedCols.getByteArray(),
0376: 0, subsetCols.getByteArray(), 0,
0377: affectedCols.getLengthInBytes());
0378: subsetCols.and(providingCols);
0379: if (subsetCols.anySetBit() == -1)
0380: continue;
0381: ((TableDescriptor) p)
0382: .setReferencedColumnMap(subsetCols);
0383: }
0384: }
0385:
0386: // generate a list of invalidations that fail.
0387: try {
0388: dep.prepareToInvalidate(p, action, lcc);
0389: } catch (StandardException sqle) {
0390:
0391: if (noInvalidate != null)
0392: sqle.setNestedException(noInvalidate);
0393:
0394: noInvalidate = sqle;
0395: }
0396: if (noInvalidate == null) {
0397:
0398: if (affectedCols != null)
0399: ((TableDescriptor) p)
0400: .setReferencedColumnMap(affectedCols);
0401:
0402: // REVISIT: future impl will want to mark the individual
0403: // dependency as invalid as well as the dependent...
0404: dep.makeInvalid(action, lcc);
0405: }
0406: }
0407:
0408: if (noInvalidate != null)
0409: throw noInvalidate;
0410: }
0411: }
0412:
0413: /**
0414: Erases all of the dependencies the dependent has, be they
0415: valid or invalid, of any dependency type. This action is
0416: usually performed as the first step in revalidating a
0417: dependent; it first erases all the old dependencies, then
0418: revalidates itself generating a list of new dependencies,
0419: and then marks itself valid if all its new dependencies are
0420: valid.
0421: <p>
0422: There might be a future want to clear all dependencies for
0423: a particular provider, e.g. when destroying the provider.
0424: However, at present, they are assumed to stick around and
0425: it is the responsibility of the dependent to erase them when
0426: revalidating against the new version of the provider.
0427: <p>
0428: clearDependencies will delete dependencies if they are
0429: stored; the delete is finalized at the next commit.
0430:
0431: @param d the dependent
0432: *
0433: * @exception StandardException Thrown on failure
0434: */
0435: public void clearDependencies(LanguageConnectionContext lcc,
0436: Dependent d) throws StandardException {
0437: clearDependencies(lcc, d, null);
0438: }
0439:
0440: /**
0441: * @inheritDoc
0442: */
0443: public void clearDependencies(LanguageConnectionContext lcc,
0444: Dependent d, TransactionController tc)
0445: throws StandardException {
0446: List deps = (List) dependents.get(d.getObjectID());
0447:
0448: synchronized (this ) {
0449: /* Remove all the stored dependencies */
0450: if (d.isPersistent()) {
0451: DataDictionary dd = getDataDictionary();
0452: boolean wait = (tc == null);
0453:
0454: dd.dropDependentsStoredDependencies(d.getObjectID(),
0455: ((wait) ? lcc.getTransactionExecute() : tc),
0456: wait);
0457: }
0458:
0459: /* Now remove the in-memory dependencies */
0460:
0461: if (deps == null)
0462: return; // already removed
0463:
0464: // go through the list notifying providers to remove
0465: // the dependency from their lists
0466: for (ListIterator depsIterator = deps.listIterator(); depsIterator
0467: .hasNext();) {
0468:
0469: Dependency dy = (Dependency) depsIterator.next();
0470: clearProviderDependency(dy.getProviderKey(), dy);
0471: }
0472:
0473: dependents.remove(d.getObjectID());
0474: }
0475: }
0476:
0477: /**
0478: * Clear the specified in memory dependency.
0479: * This is useful for clean-up when an exception occurs.
0480: * (We clear all in-memory dependencies added in the current
0481: * StatementContext.)
0482: */
0483: public void clearInMemoryDependency(Dependency dy) {
0484: synchronized (this ) {
0485: List deps = (List) dependents.get(dy.getDependent()
0486: .getObjectID());
0487:
0488: // NOTE - this is a NEGATIVE Sanity mode check, in sane mode we continue
0489: // to ensure the dependency manager is consistent.
0490: if (!SanityManager.DEBUG) {
0491: // dependency has already been removed
0492: if (deps == null)
0493: return;
0494: }
0495:
0496: List provs = (List) providers.get(dy.getProvider()
0497: .getObjectID());
0498:
0499: if (SanityManager.DEBUG) {
0500: // if both are null then everything is OK
0501: if ((deps != null) || (provs != null)) {
0502:
0503: // ensure that the Dependency dy is either
0504: // in both lists or in neither. Even if dy
0505: // is out of the list we can have non-null
0506: // deps and provs here because other dependencies
0507: // with the the same providers or dependents can exist
0508:
0509: //
0510: int depCount = 0;
0511: if (deps != null) {
0512: for (int ci = 0; ci < deps.size(); ci++) {
0513: if (dy.equals(deps.get(ci)))
0514: depCount++;
0515: }
0516: }
0517:
0518: int provCount = 0;
0519: if (provs != null) {
0520: for (int ci = 0; ci < provs.size(); ci++) {
0521: if (dy.equals(provs.get(ci)))
0522: provCount++;
0523: }
0524: }
0525:
0526: if (depCount != provCount) {
0527: SanityManager
0528: .THROWASSERT("Dependency count mismatch count in deps: "
0529: + depCount
0530: + ", count in provs "
0531: + provCount
0532: + ", dy.getDependent().getObjectID() = "
0533: + dy.getDependent()
0534: .getObjectID()
0535: + ", dy.getProvider().getObjectID() = "
0536: + dy.getProvider()
0537: .getObjectID());
0538: }
0539: }
0540:
0541: // dependency has already been removed,
0542: // matches code that is protected by !DEBUG above
0543: if (deps == null)
0544: return;
0545: }
0546:
0547: // dependency has already been removed
0548: if (provs == null)
0549: return;
0550:
0551: deps.remove(dy);
0552: if (deps.size() == 0)
0553: dependents.remove(dy.getDependent().getObjectID());
0554: provs.remove(dy);
0555: if (provs.size() == 0)
0556: providers.remove(dy.getProvider().getObjectID());
0557: }
0558: }
0559:
0560: /**
0561: * @see DependencyManager#getAllProviders
0562: *
0563: * @exception StandardException Thrown on error
0564: */
0565: // public SList getAllProviders(Dependent dependent)
0566: // throws StandardException
0567: // {
0568: // synchronized(this)
0569: // {
0570: // SList list = getProviders(dependent);
0571: // return list;
0572: // }
0573: // }
0574: /**
0575: * @see DependencyManager#getAllProviderInfos
0576: *
0577: * @exception StandardException Thrown on error
0578: */
0579: /* public ProviderInfo[] getAllProviderInfos(Dependent dependent)
0580: throws StandardException
0581: {
0582: synchronized(this)
0583: {
0584: ProviderInfo[] retval;
0585: SList list = getProviders(dependent);
0586: retval = new ProviderInfo[list.size()];
0587: if (list == null)
0588: {
0589: return retval;
0590: }
0591:
0592: int piCtr = 0;
0593:
0594: Enumeration enum = list.elements();
0595: while (enum != null && enum.hasMoreElements())
0596: {
0597: Dependency dep = (Dependency) enum.nextElement();
0598:
0599: retval[piCtr++] = new BasicProviderInfo(
0600: dep.getProvider().getObjectID(),
0601: dep.getProvider().getDependableFinder(),
0602: dep.getProvider().getObjectName()
0603: );
0604: }
0605:
0606: return retval;
0607: }
0608: }
0609: */
0610:
0611: /**
0612: * @see DependencyManager#getPersistentProviderInfos
0613: *
0614: * @exception StandardException Thrown on error
0615: */
0616: public synchronized ProviderInfo[] getPersistentProviderInfos(
0617: Dependent dependent) throws StandardException {
0618: List list = getProviders(dependent);
0619: if (list == null) {
0620: return EMPTY_PROVIDER_INFO;
0621: }
0622:
0623: java.util.ArrayList pih = new java.util.ArrayList();
0624:
0625: for (ListIterator depsIterator = list.listIterator(); depsIterator
0626: .hasNext();) {
0627: Dependency dep = (Dependency) depsIterator.next();
0628:
0629: if (dep.getProvider().isPersistent()) {
0630: pih.add(new BasicProviderInfo(dep.getProvider()
0631: .getObjectID(), dep.getProvider()
0632: .getDependableFinder(), dep.getProvider()
0633: .getObjectName()));
0634: }
0635: }
0636:
0637: return (ProviderInfo[]) pih.toArray(EMPTY_PROVIDER_INFO);
0638: }
0639:
0640: private static final ProviderInfo[] EMPTY_PROVIDER_INFO = new ProviderInfo[0];
0641:
0642: /**
0643: * @see DependencyManager#getPersistentProviderInfos
0644: *
0645: * @exception StandardException Thrown on error
0646: */
0647: public ProviderInfo[] getPersistentProviderInfos(ProviderList pl)
0648: throws StandardException {
0649: Enumeration e = pl.elements();
0650: int numProviders = 0;
0651: ProviderInfo[] retval;
0652:
0653: /*
0654: ** We make 2 passes - the first to count the number of persistent
0655: ** providers and the second to populate the array of ProviderInfos.
0656: */
0657: while (e != null && e.hasMoreElements()) {
0658: Provider prov = (Provider) e.nextElement();
0659:
0660: if (prov.isPersistent()) {
0661: numProviders++;
0662: }
0663: }
0664:
0665: e = pl.elements();
0666: retval = new ProviderInfo[numProviders];
0667: int piCtr = 0;
0668: while (e != null && e.hasMoreElements()) {
0669: Provider prov = (Provider) e.nextElement();
0670:
0671: if (prov.isPersistent()) {
0672: retval[piCtr++] = new BasicProviderInfo(prov
0673: .getObjectID(), prov.getDependableFinder(),
0674: prov.getObjectName());
0675: }
0676: }
0677:
0678: return retval;
0679: }
0680:
0681: /**
0682: * @see DependencyManager#clearColumnInfoInProviders
0683: *
0684: * @param pl provider list
0685: *
0686: * @exception StandardException Thrown on error
0687: */
0688: public void clearColumnInfoInProviders(ProviderList pl)
0689: throws StandardException {
0690: Enumeration e = pl.elements();
0691: while (e.hasMoreElements()) {
0692: Provider pro = (Provider) e.nextElement();
0693: if (pro instanceof TableDescriptor)
0694: ((TableDescriptor) pro).setReferencedColumnMap(null);
0695: }
0696: }
0697:
0698: /**
0699: * Copy dependencies from one dependent to another.
0700: *
0701: * @param copy_From the dependent to copy from
0702: * @param copyTo the dependent to copy to
0703: * @param persistentOnly only copy persistent dependencies
0704: * @param cm Current ContextManager
0705: *
0706: * @exception StandardException Thrown on error.
0707: */
0708: public void copyDependencies(Dependent copy_From, Dependent copyTo,
0709: boolean persistentOnly, ContextManager cm)
0710: throws StandardException {
0711: copyDependencies(copy_From, copyTo, persistentOnly, cm, null);
0712: }
0713:
0714: /**
0715: * @inheritDoc
0716: */
0717: public synchronized void copyDependencies(Dependent copy_From,
0718: Dependent copyTo, boolean persistentOnly,
0719: ContextManager cm, TransactionController tc)
0720: throws StandardException {
0721:
0722: List list = getProviders(copy_From);
0723: if (list == null)
0724: return;
0725:
0726: for (ListIterator depsIterator = list.listIterator(); depsIterator
0727: .hasNext();) {
0728: Provider provider = ((Dependency) depsIterator.next())
0729: .getProvider();
0730:
0731: if (!persistentOnly || provider.isPersistent()) {
0732: this .addDependency(copyTo, provider, cm, tc);
0733: }
0734: }
0735: }
0736:
0737: /**
0738: * Returns a string representation of the SQL action, hence no
0739: * need to internationalize, which is causing the invokation
0740: * of the Dependency Manager.
0741: *
0742: * @param action The action
0743: *
0744: * @return String The String representation
0745: */
0746: public String getActionString(int action) {
0747: switch (action) {
0748: case ALTER_TABLE:
0749: return "ALTER TABLE";
0750:
0751: case RENAME: //for rename table and column
0752: return "RENAME";
0753:
0754: case RENAME_INDEX:
0755: return "RENAME INDEX";
0756:
0757: case COMPILE_FAILED:
0758: return "COMPILE FAILED";
0759:
0760: case DROP_TABLE:
0761: return "DROP TABLE";
0762:
0763: case DROP_INDEX:
0764: return "DROP INDEX";
0765:
0766: case DROP_VIEW:
0767: return "DROP VIEW";
0768:
0769: case CREATE_INDEX:
0770: return "CREATE INDEX";
0771:
0772: case ROLLBACK:
0773: return "ROLLBACK";
0774:
0775: case CHANGED_CURSOR:
0776: return "CHANGED CURSOR";
0777:
0778: case CREATE_CONSTRAINT:
0779: return "CREATE CONSTRAINT";
0780:
0781: case DROP_CONSTRAINT:
0782: return "DROP CONSTRAINT";
0783:
0784: case DROP_METHOD_ALIAS:
0785: return "DROP ROUTINE";
0786:
0787: case PREPARED_STATEMENT_RELEASE:
0788: return "PREPARED STATEMENT RELEASE";
0789:
0790: case DROP_SPS:
0791: return "DROP STORED PREPARED STATEMENT";
0792:
0793: case USER_RECOMPILE_REQUEST:
0794: return "USER REQUESTED INVALIDATION";
0795:
0796: case BULK_INSERT:
0797: return "BULK INSERT";
0798:
0799: case CREATE_VIEW:
0800: return "CREATE_VIEW";
0801:
0802: case DROP_JAR:
0803: return "DROP_JAR";
0804:
0805: case REPLACE_JAR:
0806: return "REPLACE_JAR";
0807:
0808: case SET_CONSTRAINTS_ENABLE:
0809: return "SET_CONSTRAINTS_ENABLE";
0810:
0811: case SET_CONSTRAINTS_DISABLE:
0812: return "SET_CONSTRAINTS_DISABLE";
0813:
0814: case INTERNAL_RECOMPILE_REQUEST:
0815: return "INTERNAL RECOMPILE REQUEST";
0816:
0817: case CREATE_TRIGGER:
0818: return "CREATE TRIGGER";
0819:
0820: case DROP_TRIGGER:
0821: return "DROP TRIGGER";
0822:
0823: case SET_TRIGGERS_ENABLE:
0824: return "SET TRIGGERS ENABLED";
0825:
0826: case SET_TRIGGERS_DISABLE:
0827: return "SET TRIGGERS DISABLED";
0828:
0829: case MODIFY_COLUMN_DEFAULT:
0830: return "MODIFY COLUMN DEFAULT";
0831:
0832: case COMPRESS_TABLE:
0833: return "COMPRESS TABLE";
0834:
0835: case DROP_COLUMN:
0836: return "DROP COLUMN";
0837:
0838: case DROP_STATISTICS:
0839: return "DROP STATISTICS";
0840:
0841: case UPDATE_STATISTICS:
0842: return "UPDATE STATISTICS";
0843:
0844: case TRUNCATE_TABLE:
0845: return "TRUNCATE TABLE";
0846:
0847: case DROP_SYNONYM:
0848: return "DROP SYNONYM";
0849:
0850: case REVOKE_PRIVILEGE:
0851: return "REVOKE PRIVILEGE";
0852:
0853: case REVOKE_PRIVILEGE_RESTRICT:
0854: return "REVOKE PRIVILEGE RESTRICT";
0855:
0856: default:
0857: if (SanityManager.DEBUG) {
0858: SanityManager
0859: .THROWASSERT("getActionString() passed an invalid value ("
0860: + action + ")");
0861: }
0862: // NOTE: This is not internationalized because we should never
0863: // reach here.
0864: return "UNKNOWN";
0865: }
0866: }
0867:
0868: /**
0869: * Count the number of active dependencies, both stored and in memory,
0870: * in the system.
0871: *
0872: * @return int The number of active dependencies in the system.
0873:
0874: @exception StandardException thrown if something goes wrong
0875: */
0876: public int countDependencies() throws StandardException {
0877: synchronized (this ) {
0878: int numDependencies = 0;
0879: Enumeration deps = dependents.elements();
0880: Enumeration provs = providers.elements();
0881: List storedDeps = getDataDictionary()
0882: .getAllDependencyDescriptorsList();
0883:
0884: /* Count the in memory dependencies */
0885: while (deps.hasMoreElements()) {
0886: numDependencies += ((List) deps.nextElement()).size();
0887: }
0888:
0889: while (provs.hasMoreElements()) {
0890: numDependencies += ((List) provs.nextElement()).size();
0891: }
0892:
0893: /* Add in the stored dependencies */
0894: numDependencies += storedDeps.size();
0895:
0896: return numDependencies;
0897: }
0898: }
0899:
0900: /**
0901: * Dump out debugging info on all of the dependencies currently
0902: * within the system.
0903: *
0904: * @return String Debugging info on the dependencies.
0905: * (null if SanityManger.DEBUG is false)
0906:
0907: * @exception StandardException thrown if something goes wrong
0908: * @exception java.sql.SQLException thrown if something goes wrong
0909: */
0910: public String dumpDependencies() throws StandardException,
0911: java.sql.SQLException {
0912: synchronized (this ) {
0913: boolean foundInMemory = false;
0914: boolean foundStored = false;
0915: StringBuffer debugBuf = new StringBuffer();
0916:
0917: if (SanityManager.DEBUG) {
0918: Enumeration deps = dependents.keys();
0919: UUID[] depKeys = new UUID[dependents.size()];
0920:
0921: /* Record the in memory dependencies */
0922: for (int i = 0; deps.hasMoreElements(); i++) {
0923: /*
0924: ** Get all the keys and sort them, so that they will always
0925: ** be printed in the same order (we have tests that canonize
0926: ** the order of printing the dependencies, and since the key
0927: ** is a UUID, the order they are returned from
0928: ** hasMoreElements() changes from run to run).
0929: */
0930: depKeys[i] = (UUID) deps.nextElement();
0931: }
0932:
0933: /* Do a bubble sort - there aren't likely to be many elements */
0934: bubbleSort(depKeys);
0935:
0936: /* Iterate through the sorted keys */
0937: for (int i = 0; i < depKeys.length; i++) {
0938: List depsSList = (List) dependents.get(depKeys[i]);
0939:
0940: for (ListIterator depsIterator = depsSList
0941: .listIterator(); depsIterator.hasNext();) {
0942: Dependency dy = (Dependency) depsIterator
0943: .next();
0944:
0945: if (!foundInMemory) {
0946: debugBuf
0947: .append("In Memory Dependencies:\n");
0948: foundInMemory = true;
0949: }
0950:
0951: debugBuf.append(dy.getDependent().toString()
0952: + ", type "
0953: + dy.getDependent().getClassType()
0954: + ", " + " is dependent on "
0955: + dy.getProvider().getObjectName()
0956: + ", type "
0957: + dy.getProvider().getClassType()
0958: + "\n");
0959: }
0960: }
0961:
0962: /* Record the in memory dependencies */
0963: Enumeration provs = providers.keys();
0964: UUID[] provKeys = new UUID[providers.size()];
0965: for (int i = 0; provs.hasMoreElements(); i++) {
0966: /*
0967: ** Get all the keys and sort them, so that they will always
0968: ** be printed in the same order (we have tests that canonize
0969: ** the order of printing the dependencies, and since the key
0970: ** is a UUID, the order they are returned from
0971: ** hasMoreElements() changes from run to run).
0972: */
0973: provKeys[i] = (UUID) provs.nextElement();
0974: }
0975:
0976: /* Do a bubble sort - there aren't likely to be many elements */
0977: bubbleSort(provKeys);
0978:
0979: /* Iterate through the sorted keys */
0980: for (int i = 0; i < provKeys.length; i++) {
0981: List depsSList = (List) providers.get(provKeys[i]);
0982:
0983: for (ListIterator depsIterator = depsSList
0984: .listIterator(); depsIterator.hasNext();) {
0985:
0986: Dependency dy = (Dependency) depsIterator
0987: .next();
0988:
0989: if (!foundInMemory) {
0990: debugBuf
0991: .append("In Memory Dependencies:\n");
0992: foundInMemory = true;
0993: }
0994:
0995: debugBuf.append(dy.getProvider().toString()
0996: + ", type "
0997: + dy.getProvider().getClassType()
0998: + ", provides for "
0999: + dy.getDependent().getObjectName()
1000: + ", type "
1001: + dy.getDependent().getClassType()
1002: + "\n");
1003: }
1004: }
1005: /* Record the stored dependencies in sorted order to avoid
1006: ordering problems in canons. Also the dependencyDescriptor.getUUID()
1007: in this list is not unique, hence the sort on the output string values instead
1008: */
1009: List storedDeps = getDataDictionary()
1010: .getAllDependencyDescriptorsList();
1011:
1012: String[] dependStr = new String[storedDeps.size()];
1013:
1014: int i = 0;
1015: for (ListIterator depsIterator = storedDeps
1016: .listIterator(); depsIterator.hasNext();) {
1017: DependencyDescriptor dd = (DependencyDescriptor) depsIterator
1018: .next();
1019:
1020: if (!foundStored) {
1021: debugBuf.append("Stored Dependencies:\n");
1022: foundStored = true;
1023: }
1024:
1025: dependStr[i++] = new String(dd.getProviderFinder()
1026: .getSQLObjectName(
1027: dd.getProviderID().toString())
1028: + ", type "
1029: + dd.getProviderFinder().getSQLObjectType()
1030: + ", provides for "
1031: + dd.getDependentFinder().getSQLObjectName(
1032: dd.getUUID().toString())
1033: + ", type "
1034: + dd.getDependentFinder()
1035: .getSQLObjectType() + "\n");
1036: }
1037:
1038: // sort stored dependencies; dependStr
1039: for (i = 0; i < dependStr.length; i++) {
1040: for (int j = i + 1; j < dependStr.length; j++) {
1041: if (dependStr[i].compareTo(dependStr[j]) > 0) {
1042: String save = dependStr[i];
1043: dependStr[i] = dependStr[j];
1044: dependStr[j] = save;
1045: }
1046: }
1047: }
1048:
1049: for (i = 0; i < dependStr.length; i++)
1050: debugBuf.append(dependStr[i]);
1051:
1052: }
1053:
1054: return debugBuf.toString();
1055: }
1056: }
1057:
1058: //
1059: // class interface
1060: //
1061: public BasicDependencyManager() {
1062: }
1063:
1064: //
1065: // class implementation
1066: //
1067:
1068: /**
1069: * Add a new dependency to the specified table if it does not
1070: * already exist in that table.
1071: *
1072: * @return boolean Whether or not the dependency get added.
1073: */
1074: private boolean addDependencyToTable(Hashtable table, Object key,
1075: Dependency dy) {
1076:
1077: List deps = (List) table.get(key);
1078: if (deps == null) {
1079: deps = newSList();
1080: deps.add(dy);
1081: table.put(key, deps);
1082: } else {
1083: /* Make sure that we're not adding a duplicate dependency */
1084: UUID provKey = dy.getProvider().getObjectID();
1085: UUID depKey = dy.getDependent().getObjectID();
1086:
1087: for (ListIterator depsIT = deps.listIterator(); depsIT
1088: .hasNext();) {
1089: Dependency curDY = (Dependency) depsIT.next();
1090: if (curDY.getProvider().getObjectID().equals(provKey)
1091: && curDY.getDependent().getObjectID().equals(
1092: depKey)) {
1093: return false;
1094: }
1095: }
1096:
1097: deps.add(dy);
1098: }
1099:
1100: if (SanityManager.DEBUG) {
1101:
1102: if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
1103:
1104: if (table.size() > 100)
1105: System.out
1106: .println("memoryLeakTrace:BasicDependencyManager:table "
1107: + table.size());
1108: if (deps.size() > 50)
1109: System.out
1110: .println("memoryLeakTrace:BasicDependencyManager:deps "
1111: + deps.size());
1112: }
1113: }
1114:
1115: return true;
1116: }
1117:
1118: /**
1119: * removes a dependency for a given provider. assumes
1120: * that the dependent removal is being dealt with elsewhere.
1121: * Won't assume that the dependent only appears once in the list.
1122: */
1123: protected void clearProviderDependency(UUID p, Dependency d) {
1124: List deps = (List) providers.get(p);
1125:
1126: if (deps == null)
1127: return;
1128:
1129: deps.remove(d);
1130:
1131: if (deps.size() == 0)
1132: providers.remove(p);
1133: }
1134:
1135: /**
1136: * Replace the DependencyDescriptors in an List with Dependencys.
1137: *
1138: * @param storedList The List of DependencyDescriptors representing
1139: * stored dependencies.
1140: * @param providerForList The provider if this list is being created
1141: * for a list of dependents. Null otherwise.
1142: *
1143: * @return List The converted List
1144: *
1145: * @exception StandardException thrown if something goes wrong
1146: */
1147: private List getDependencyDescriptorList(List storedList,
1148: Provider providerForList) throws StandardException {
1149: if (storedList.size() != 0) {
1150: /* For each DependencyDescriptor, we need to instantiate
1151: * object descriptors of the appropriate type for both
1152: * the dependent and provider, create a Dependency with
1153: * that Dependent and Provider and substitute the Dependency
1154: * back into the same place in the List
1155: * so that the call gets an enumerations of Dependencys.
1156: */
1157: for (ListIterator depsIterator = storedList.listIterator(); depsIterator
1158: .hasNext();) {
1159: Dependent tempD;
1160: Provider tempP;
1161: DependableFinder finder = null;
1162:
1163: DependencyDescriptor depDesc = (DependencyDescriptor) depsIterator
1164: .next();
1165:
1166: try {
1167: finder = depDesc.getDependentFinder();
1168: tempD = (Dependent) finder.getDependable(depDesc
1169: .getUUID());
1170:
1171: if (providerForList != null) {
1172: // Use the provider being passed in.
1173: tempP = providerForList;
1174:
1175: // Sanity check the object identifiers match.
1176: if (SanityManager.DEBUG) {
1177: if (!tempP.getObjectID().equals(
1178: depDesc.getProviderID())) {
1179: SanityManager
1180: .THROWASSERT("mismatch providers");
1181: }
1182: }
1183: } else {
1184: finder = depDesc.getProviderFinder();
1185: tempP = (Provider) finder.getDependable(depDesc
1186: .getProviderID());
1187:
1188: }
1189:
1190: } catch (java.sql.SQLException te) {
1191: throw StandardException.newException(
1192: SQLState.DEP_UNABLE_TO_RESTORE, finder
1193: .getClass().getName(), te
1194: .getMessage());
1195:
1196: }
1197:
1198: depsIterator.set(new BasicDependency(tempD, tempP));
1199: }
1200: }
1201:
1202: return storedList;
1203: }
1204:
1205: /**
1206: * Returns the DataDictionary to use.
1207: *
1208: * @return DataDictionary The DataDictionary to use.
1209: */
1210: private DataDictionary getDataDictionary() {
1211: if (dataDictionary == null) {
1212: DataDictionaryContext ddc;
1213:
1214: ddc = (DataDictionaryContext) (ContextService
1215: .getContext(DataDictionaryContext.CONTEXT_ID));
1216:
1217: dataDictionary = ddc.getDataDictionary();
1218: }
1219:
1220: return dataDictionary;
1221: }
1222:
1223: /**
1224: * Returns the LanguageConnectionContext to use.
1225: *
1226: * @return LanguageConnectionContext The LanguageConnectionContext to use.
1227: */
1228: private LanguageConnectionContext getLanguageConnectionContext() {
1229: // find the language context.
1230: return (LanguageConnectionContext) ContextService
1231: .getContext(LanguageConnectionContext.CONTEXT_ID);
1232: }
1233:
1234: /**
1235: * Returns the LanguageConnectionContext to use.
1236: *
1237: * @param cm Current ContextManager
1238: *
1239: * @return LanguageConnectionContext The LanguageConnectionContext to use.
1240: */
1241: private LanguageConnectionContext getLanguageConnectionContext(
1242: ContextManager cm) {
1243: // find the language context.
1244: return (LanguageConnectionContext) cm
1245: .getContext(LanguageConnectionContext.CONTEXT_ID);
1246: }
1247:
1248: /**
1249: * Do a bubble sort on the given array of UUIDs. This sorts by the
1250: * String values of the UUIDs. It's slow, but it doesn't matter
1251: * because this is only for testing and debugging. Sorting by
1252: * UUID.toString() always gives the same order because, within a
1253: * single boot of the system, UUIDs are distinguished only by a
1254: * sequence number.
1255: *
1256: * @param uuids The array of UUIDs to sort.
1257: */
1258: private void bubbleSort(UUID[] uuids) {
1259: if (SanityManager.DEBUG) {
1260: for (int i = 0; i < uuids.length; i++) {
1261: for (int j = i + 1; j < uuids.length; j++) {
1262: if (uuids[i].toString().compareTo(
1263: uuids[j].toString()) > 0) {
1264: UUID save = uuids[i];
1265: uuids[i] = uuids[j];
1266: uuids[j] = save;
1267: }
1268: }
1269: }
1270: }
1271: }
1272:
1273: /**
1274: Returns an enumeration of all dependencies that this
1275: dependent has with any provider (even
1276: invalid ones). Includes all dependency types.
1277:
1278: @param d the dependent
1279:
1280: @exception StandardException thrown if something goes wrong
1281: */
1282: private List getProviders(Dependent d) throws StandardException {
1283:
1284: List deps = (List) dependents.get(d.getObjectID());
1285:
1286: /* If the Dependent is not persistent, then we only have to
1287: * worry about in-memory dependencies. Otherwise, we have to
1288: * integrate the 2.
1289: */
1290: if (!d.isPersistent()) {
1291: return (deps == null ? null : deps);
1292: } else {
1293: if (deps == null) {
1294: deps = newSList();
1295: } else {
1296: deps = newSList(deps);
1297: }
1298:
1299: /* Now we need to add any persistent dependencies to the
1300: * list before returning
1301: */
1302: List storedList = getDependencyDescriptorList(
1303: getDataDictionary().getDependentsDescriptorList(
1304: d.getObjectID().toString()),
1305: (Provider) null);
1306:
1307: if (storedList.size() > 0) {
1308: deps.addAll(0, storedList);
1309: }
1310:
1311: return deps;
1312: }
1313: }
1314:
1315: /**
1316: Returns an enumeration of all dependencies that this
1317: provider is supporting for any dependent at all (even
1318: invalid ones). Includes all dependency types.
1319:
1320: @param p the provider
1321:
1322: @exception StandardException thrown if something goes wrong
1323: */
1324: private List getDependents(Provider p) throws StandardException {
1325:
1326: List deps = (List) providers.get(p.getObjectID());
1327:
1328: /* If the Provider is not persistent, then we only have to
1329: * worry about in-memory dependencies. Otherwise, we have to
1330: * integrate the 2.
1331: */
1332: if (!p.isPersistent()) {
1333: return deps;
1334: } else {
1335: if (deps == null) {
1336: deps = newSList();
1337: } else {
1338: deps = newSList(deps);
1339: }
1340:
1341: /* Now we need to add any persistent dependencies to the
1342: * list before returning
1343: */
1344: List storedList = getDependencyDescriptorList(
1345: getDataDictionary().getProvidersDescriptorList(
1346: p.getObjectID().toString()), p);
1347: if (storedList.size() > 0) {
1348: deps.addAll(0, storedList);
1349: }
1350:
1351: return deps;
1352: }
1353: }
1354:
1355: private static List newSList() {
1356: return java.util.Collections
1357: .synchronizedList(new java.util.LinkedList());
1358: }
1359:
1360: private static List newSList(List list) {
1361: return java.util.Collections
1362: .synchronizedList(new java.util.LinkedList(list));
1363: }
1364:
1365: private DataDictionary dataDictionary = null;
1366: protected Hashtable dependents = new Hashtable();
1367: protected Hashtable providers = new Hashtable();
1368: }
|