📄 basicdependencymanager.java
字号:
/* Derby - Class org.apache.derby.impl.sql.depend.BasicDependencyManager Copyright 1997, 2005 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.sql.depend;import org.apache.derby.catalog.Dependable;import org.apache.derby.catalog.DependableFinder;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.services.context.ContextService;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.sql.compile.CompilerContext;import org.apache.derby.iapi.sql.compile.Parser;import org.apache.derby.impl.sql.compile.CreateViewNode;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;import org.apache.derby.iapi.sql.conn.StatementContext;import org.apache.derby.iapi.sql.depend.DependencyManager;import org.apache.derby.iapi.sql.depend.Dependency;import org.apache.derby.iapi.sql.depend.Dependent;import org.apache.derby.iapi.sql.depend.Provider;import org.apache.derby.iapi.sql.depend.ProviderInfo;import org.apache.derby.iapi.sql.depend.ProviderList;import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;import org.apache.derby.iapi.sql.dictionary.DataDictionary;import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;import org.apache.derby.iapi.sql.dictionary.DependencyDescriptor;import org.apache.derby.iapi.sql.dictionary.TableDescriptor;import org.apache.derby.iapi.sql.dictionary.ViewDescriptor;import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;import org.apache.derby.impl.sql.catalog.DDColumnDependableFinder;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.catalog.UUID;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.services.io.FormatableBitSet;import org.apache.derby.iapi.reference.MessageId;import org.apache.derby.iapi.error.StandardException;import java.util.Hashtable;import java.util.Enumeration;import java.util.ListIterator;import java.util.List;/** The dependency manager tracks needs that dependents have of providers. */public class BasicDependencyManager implements DependencyManager { // // DependencyManager interface // /** adds a dependency from the dependent on the provider. This will be considered to be the default type of dependency, when dependency types show up. <p> Implementations of addDependency should be fast -- performing alot of extra actions to add a dependency would be a detriment. @param d the dependent @param p the provider @exception StandardException thrown if something goes wrong */ public void addDependency(Dependent d, Provider p, ContextManager cm) throws StandardException { synchronized(this) { Dependency dy = new BasicDependency(d, p); /* Dependencies are either in-memory or stored, but not both */ if (! d.isPersistent() || ! p.isPersistent()) { /* Duplicate dependencies are not added to the lists. * If we find that the dependency we are trying to add in * one list is a duplicate, then it should be a duplicate in the * other list. */ boolean addedToDeps = false; boolean addedToProvs = false; addedToDeps = addDependencyToTable(dependents, d.getObjectID(), dy); if (addedToDeps) { addedToProvs = addDependencyToTable(providers, p.getObjectID(), dy); } else if (SanityManager.DEBUG) { addedToProvs = addDependencyToTable(providers, p.getObjectID(), dy); } /* Dependency should have been added to both or neither */ if (SanityManager.DEBUG) { if (addedToDeps != addedToProvs) { SanityManager.THROWASSERT( "addedToDeps (" + addedToDeps + ") and addedToProvs (" + addedToProvs + ") are expected to agree"); } } /* Add the dependency to the StatementContext, so that * it can be cleared on a pre-execution error. */ StatementContext sc = (StatementContext) cm.getContext(org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT); sc.addDependency(dy); } else { /* Add a stored dependency */ LanguageConnectionContext lcc = getLanguageConnectionContext(cm); DataDictionary dd = getDataDictionary(); DependencyDescriptor dependencyDescriptor; dependencyDescriptor = new DependencyDescriptor(d, p); /* We can finally call the DataDictionary to store the dependency */ dd.addDescriptor(dependencyDescriptor, null, DataDictionary.SYSDEPENDS_CATALOG_NUM, true, lcc.getTransactionExecute()); } } } /** drops a single dependency @param d the dependent @param p the provider @exception StandardException thrown if something goes wrong */ private void dropDependency(LanguageConnectionContext lcc, Dependent d, Provider p) throws StandardException { if (SanityManager.DEBUG) { // right now, this routine isn't called for in-memory dependencies if (! d.isPersistent() || ! p.isPersistent()) { SanityManager.NOTREACHED(); } } DataDictionary dd = getDataDictionary(); DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(d, p); dd.dropStoredDependency( dependencyDescriptor, lcc.getTransactionExecute() ); } /** mark all dependencies on the named provider as invalid. When invalidation types show up, this will use the default invalidation type. The dependencies will still exist once they are marked invalid; clearDependencies should be used to remove dependencies that a dependent has or provider gives. <p> Implementations of this can take a little time, but are not really expected to recompile things against any changes made to the provider that caused the invalidation. The dependency system makes no guarantees about the state of the provider -- implementations can call this before or after actually changing the provider to its new state. <p> Implementations should throw StandardException if the invalidation should be disallowed. @param p the provider @param action The action causing the invalidate @exception StandardException thrown if unable to make it invalid */ public void invalidateFor(Provider p, int action, LanguageConnectionContext lcc) throws StandardException { /* ** Non-persistent dependencies are stored in memory, and need to ** use "synchronized" to ensure their lists don't change while ** the invalidation is taking place. Persistent dependencies are ** stored in the data dictionary, and we should *not* do anything ** transactional (like reading from a system table) from within ** a synchronized method, as it could cause deadlock. ** ** Presumably, the transactional locking in the data dictionary ** is enough to protect us, so that we don't have to put any ** synchronization in the DependencyManager. */ if (p.isPersistent()) coreInvalidateFor(p, action, lcc); else { synchronized (this) { coreInvalidateFor(p, action, lcc); } } } /** * A version of invalidateFor that does not provide synchronization among * invalidators. If parameter "forSync" is true, it also provides * synchronization on the dependents. Currently, this means synchronizing * on the prepared statements, which might be being executed on other * threads. * @param p provider * @param action The action causing the invalidate * @param lcc Language connection context * * @return array of locked dependents (to be unlocked by caller later) * * @exception StandardException Thrown on error. */ private void coreInvalidateFor(Provider p, int action, LanguageConnectionContext lcc) throws StandardException { List list = getDependents(p); if (list == null) { return; } // affectedCols is passed in from table descriptor provider to indicate // which columns it cares; subsetCols is affectedCols' intersection // with column bit map found in the provider of SYSDEPENDS line to // find out which columns really matter. If SYSDEPENDS line's // dependent is view (or maybe others), provider is table, yet it // doesn't have column bit map because the view was created in a // previous version of server which doesn't support column dependency, // and we really want it to have (such as in drop column), in any case // if we passed in table descriptor to this function with a bit map, // we really need this, we generate the bitmaps on the fly and update // SYSDEPENDS FormatableBitSet affectedCols = null, subsetCols = null; if (p instanceof TableDescriptor) { affectedCols = ((TableDescriptor) p).getReferencedColumnMap(); if (affectedCols != null) subsetCols = new FormatableBitSet(affectedCols.getLength()); } { StandardException noInvalidate = null; // We cannot use an iterator here as the invalidations can remove // entries from this list. for (int ei = list.size() - 1; ei >= 0; ei--) { if (ei >= list.size()) continue; Dependency dependency = (Dependency) list.get(ei); Dependent dep = dependency.getDependent(); if (affectedCols != null) { TableDescriptor td = (TableDescriptor) dependency.getProvider(); FormatableBitSet providingCols = td.getReferencedColumnMap(); if (providingCols == null) { if (dep instanceof ViewDescriptor) { ViewDescriptor vd = (ViewDescriptor) dep; DataDictionary dd = getDataDictionary(); SchemaDescriptor compSchema; compSchema = dd.getSchemaDescriptor(vd.getCompSchemaId(), null); CompilerContext newCC = lcc.pushCompilerContext(compSchema); Parser pa = newCC.getParser(); LanguageConnectionFactory lcf = lcc.getLanguageConnectionFactory(); // Since this is always nested inside another SQL // statement, so topLevel flag should be false CreateViewNode cvn = (CreateViewNode)pa.parseStatement( vd.getViewText()); // need a current dependent for bind newCC.setCurrentDependent(dep); cvn = (CreateViewNode) cvn.bind(); ProviderInfo[] providerInfos = cvn.getProviderInfo(); lcc.popCompilerContext(newCC); boolean interferent = false; for (int i = 0; i < providerInfos.length; i++) { Provider provider = null; try { provider = (Provider) providerInfos[i]. getDependableFinder(). getDependable( providerInfos[i].getObjectId()); } catch(java.sql.SQLException te) { if (SanityManager.DEBUG) { SanityManager.THROWASSERT("unexpected java.sql.SQLException - " + te); } } if (provider instanceof TableDescriptor) { TableDescriptor tab = (TableDescriptor)provider; FormatableBitSet colMap = tab.getReferencedColumnMap(); if (colMap == null) continue; // if later on an error is raised such as in // case of interference, this dependency line // upgrade will not happen due to rollback tab.setReferencedColumnMap(null); dropDependency(lcc, vd, tab); tab.setReferencedColumnMap(colMap); addDependency(vd, tab, lcc.getContextManager()); if (tab.getObjectID().equals(td.getObjectID())) { System.arraycopy(affectedCols.getByteArray(), 0, subsetCols.getByteArray(), 0, affectedCols.getLengthInBytes()); subsetCols.and(colMap); if (subsetCols.anySetBit() != -1) { interferent = true; ((TableDescriptor) p).setReferencedColumnMap(subsetCols); } } } // if provider instanceof TableDescriptor } // for providerInfos if (! interferent) continue; } // if dep instanceof ViewDescriptor else ((TableDescriptor) p).setReferencedColumnMap(null); } // if providingCols == null else { System.arraycopy(affectedCols.getByteArray(), 0, subsetCols.getByteArray(), 0, affectedCols.getLengthInBytes()); subsetCols.and(providingCols); if (subsetCols.anySetBit() == -1) continue; ((TableDescriptor) p).setReferencedColumnMap(subsetCols); } } // generate a list of invalidations that fail. try { dep.prepareToInvalidate(p, action, lcc); } catch (StandardException sqle) { if (noInvalidate != null) sqle.setNestedException(noInvalidate); noInvalidate = sqle; } if (noInvalidate == null) { if (affectedCols != null) ((TableDescriptor) p).setReferencedColumnMap(affectedCols); // REVISIT: future impl will want to mark the individual // dependency as invalid as well as the dependent... dep.makeInvalid(action, lcc); } } if (noInvalidate != null) throw noInvalidate; } } /** Erases all of the dependencies the dependent has, be they valid or invalid, of any dependency type. This action is usually performed as the first step in revalidating a dependent; it first erases all the old dependencies, then revalidates itself generating a list of new dependencies, and then marks itself valid if all its new dependencies are valid. <p> There might be a future want to clear all dependencies for a particular provider, e.g. when destroying the provider. However, at present, they are assumed to stick around and it is the responsibility of the dependent to erase them when revalidating against the new version of the provider. <p> clearDependencies will delete dependencies if they are stored; the delete is finalized at the next commit. @param d the dependent @param p the provider * * @exception StandardException Thrown on failure */ public void clearDependencies(LanguageConnectionContext lcc, Dependent d) throws StandardException { List deps = (List) dependents.get(d.getObjectID()); synchronized(this) { /* Remove all the stored dependencies */ if (d.isPersistent()) { DataDictionary dd = getDataDictionary(); dd.dropDependentsStoredDependencies(d.getObjectID(), lcc.getTransactionExecute()); } /* Now remove the in-memory dependencies */ if (deps == null) return; // already removed // go through the list notifying providers to remove // the dependency from their lists for (ListIterator depsIterator = deps.listIterator(); depsIterator.hasNext(); ) { Dependency dy = (Dependency)depsIterator.next(); clearProviderDependency(dy.getProviderKey(), dy); } dependents.remove(d.getObjectID()); } } /** * Clear the specified in memory dependency. * This is useful for clean-up when an exception occurs. * (We clear all in-memory dependencies added in the current * StatementContext.) */ public void clearInMemoryDependency(Dependency dy)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -