The simplest things for DependencyType and InvalidType to be are integer id's or strings, rather than complex objects.
In terms of ensuring that no makeInvalid calls are made until we have identified all objects that could be, so that the calls will be made from "leaf" invalid objects (those not in turn relied on by other dependents) to dependent objects upon which others depend, the dependency manager will need to maintain an internal queue of dependencies and make the calls once it has completes its analysis of the dependencies of which it is aware. Since it is much simpler and potentially faster for makeInvalid calls to be made as soon as the dependents are identified, separate implementations may be called for, or separate interfaces to trigger the different styles of invalidation.
In terms of separate interfaces, the DependencyManager might have two methods,
void makeInvalidImmediate(); void makeInvalidOrdered();or a flag on the makeInvalid method to choose the style to use.
In terms of separate implementations, the ImmediateInvalidate manager might have simpler internal structures for tracking dependencies than the OrderedInvalidate manager.
The language system doesn't tend to suffer from this ordering problem, as it tends to handle the impact of invalidation by simply deferring recompilation until the next execution. So, a prepared statement might be invalidated several times by a transaction that contains several DDL operations, and only recompiled once, at its next execution. This is sufficient for the common use of a system, where DDL changes tend to be infrequent and clustered.
There could be ways to push this "ordering problem" out of the dependency system, but since it knows when it starts and when it finished finding all of the invalidating actions, it is likely the best home for this.
One other problem that could arise is multiple invalidations occurring one after another. The above design of the dependency system can really only react to each invalidation request as a unit, not to multiple invalidation requests.
Another extension that might be desired is for the dependency manager to provide for cascading invalidations -- that is, if it finds and marks one Dependent object as invalid, if that object can also be a provider, to look for its dependent objects and cascade the dependency on to them. This can be a way to address the multiple-invalidation request need, if it should arise. The simplest way to do this is to always cascade the same invalidation type; otherwise, dependents need to be able to say what a certain type of invalidation type gets changed to when it is handed on.
The basic language system does not need support for cascaded dependencies -- statements do not depend on other statements in a way that involves the dependency system.
I do not know if it would be worthwhile to consider using the dependency manager to aid in the implementation of the SQL DROP statements or not. Past implementations of database systems have not used the dependency system to implement this functionality, but have instead hard-coded the lookups like so:
in DropTable: scan the TableAuthority table looking for authorities on this table; drop any that are found. scan the ColumnAuthority table looking for authorities on this table; drop any that are found. scan the View table looking for views on this table; drop any that are found. scan the Column table looking for rows for columns of this table; drop any that are found. scan the Constraint table looking for rows for constraints of this table; drop any that are found. scan the Index table looking for rows for indexes of this table; drop the indexes, and any rows that are found. drop the table's conglomerate drop the table's row in the Table table.
The direct approach such as that outlined in the example will probably be quicker and is definitely "known technology" over the use of a dependency system in this area.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|