The ConglomerateDescriptor class is used to get information about
conglomerates for the purpose of optimization.
A ConglomerateDescriptor can map to a base table, an index
or a index backing a constraint. Multiple ConglomerateDescriptors
can map to a single underlying store conglomerate, such as when
multiple index definitions share a physical file.
NOTE: The language module does not have to know much about conglomerates
with this architecture. To get the cost of using a conglomerate, all it
has to do is pass the ConglomerateDescriptor to the access methods, along
with the predicate. What the access methods need from a
ConglomerateDescriptor remains to be seen.
Method from org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor Detail: |
public ConglomerateDescriptor describeSharedConglomerate(ConglomerateDescriptor[] descriptors,
boolean ignoreThis) throws StandardException {
/* Descriptor for the heap always correctly describes the
* physical conglomerate, as sharing of the heap is not
* allowed. So if this is a heap descriptor and "descriptors"
* has any entries whose conglomerate number matches this
* descriptor's conglomerate number, then that element should
* be the same descriptor as "this".
*/
if (!isIndex())
{
ConglomerateDescriptor heap = null;
for (int i = 0; i < descriptors.length; i++)
{
if (getConglomerateNumber() !=
descriptors[i].getConglomerateNumber())
{
continue;
}
if (SanityManager.DEBUG)
{
if (!descriptors[i].getUUID().equals(getUUID()))
{
SanityManager.THROWASSERT(
"Should not have multiple descriptors for " +
"heap conglomerate " + getConglomerateNumber());
}
}
heap = descriptors[i];
}
return heap;
}
/* In order to be shared by multiple conglomerate descriptors
* the physical conglomerate must necessarily satisfy the
* following criteria:
*
* 1. If any of the sharing descriptors is unique, then
* the physical conglomerate must also be unique.
*
* 2. If none of sharing descriptors are unique and any of
* the descriptors are UniqueWithDuplicateNulls the physical
* conglomerate must also be UniqueWithDuplicateNulls
*
* 3. If none of the sharing descriptors are unique or
* UniqueWithDuplicateNulls, the physical conglomerate
* must not be unique.
*
* 4. If the physical conglomerate has n columns, then all
* sharing descriptors must have n columns, as well.
*
* These criteria follow from the "share conglom" detection logic
* found in CreateIndexConstantAction.executeConstantAction().
* See that class for details.
*
* So walk through the conglomerate descriptors that share
* a conglomerate with this one and see if any of them is
* unique.
*/
ConglomerateDescriptor returnDesc = null;
for (int i = 0; i < descriptors.length; i++)
{
// Skip if it's not an index (i.e. it's a heap descriptor).
if (!descriptors[i].isIndex())
continue;
// Skip if it doesn't share with "this".
if (getConglomerateNumber() !=
descriptors[i].getConglomerateNumber())
{
continue;
}
// Skip if ignoreThis is true and it describes "this".
if (ignoreThis &&
getUUID().equals(descriptors[i].getUUID()))
{
continue;
}
if (descriptors[i].getIndexDescriptor().isUnique())
{
/* Given criteria #1 and #4 described above, if we
* have a unique conglomerate descriptor then we've
* found what we need, so we're done.
*/
returnDesc = descriptors[i];
break;
}
if (descriptors[i].getIndexDescriptor()
.isUniqueWithDuplicateNulls())
{
/* Criteria #2. Remember this descriptor. If we don't find
* any unique descriptor we will use this.
*/
returnDesc = descriptors[i];
}
else if (returnDesc == null)
{
/* Criteria #3 If no other descriptor found satifying
* #1 or #2 this descriptor will be used.
*/
returnDesc = descriptors[i];
}
}
if (SanityManager.DEBUG)
{
if (returnDesc == null)
{
SanityManager.THROWASSERT(
"Failed to find sharable conglomerate descriptor " +
"for index conglomerate # " + getConglomerateNumber());
}
}
return returnDesc;
}
This method searches the received array of conglom descriptors
to find all descriptors that currently share a physical conglom
with "this". The method then searches within those sharing
descriptors to find one that fully describes what a physical
conglom would have to look like in order to support _all_ of
the sharing descriptors in the array--esp. one that correctly
enforces the uniqueness requirements for those descriptors. |
public ConglomerateDescriptor drop(LanguageConnectionContext lcc,
TableDescriptor td) throws StandardException {
DataDictionary dd = getDataDictionary();
DependencyManager dm = dd.getDependencyManager();
TransactionController tc = lcc.getTransactionExecute();
// invalidate any prepared statements that
// depended on the index (including this one)
dm.invalidateFor(this, DependencyManager.DROP_INDEX, lcc);
// only drop the conglomerate if no similar index but with different
// name. Get from dd in case we drop other dup indexes with a cascade operation
ConglomerateDescriptor [] congDescs =
dd.getConglomerateDescriptors(getConglomerateNumber());
boolean dropConglom = false;
ConglomerateDescriptor physicalCD = null;
if (congDescs.length == 1)
dropConglom = true;
else
{
/* There are multiple conglomerate descriptors which share
* the same physical conglomerate. That said, if we are
* dropping the *ONLY* conglomerate descriptor that fully
* matches the physical conglomerate, then we have to do
* a little extra work. Namely, if the physical conglomerate
* is unique and this descriptor is unique, but none of the
* other descriptors which share with this one are unique,
* then we have to "update" the physical conglomerate to
* be non-unique. This ensures correct behavior for the
* remaining descriptors. (DERBY-3299)
*
* Note that "update the physical conglomerate" above is
* currently implemented as "drop the old conglomerate"
* (now) and "create a new (replacement) one" (later--let
* the caller do it). Possible improvements to that logic
* may be desirable in the future...
*/
boolean needNewConglomerate;
/* Find a conglomerate descriptor that fully describes what
* a physical conglomerate would have to look like in order
* to fulfill the requirements (esp. uniqueness) of _all_
* conglomerate descriptors which share a physical conglomerate
* with this one. "true" in the next line means that when we
* search for such a conglomerate, we should ignore "this"
* descriptor--because we're going to drop this one and we
* want to see what the physical conglomerate must look like
* when "this" descriptor does not exist. Note that this
* call should never return null because we only get here
* if more than one descriptor shares a conglom with this
* one--so at the very least we'll have two descriptors,
* which means the following call should return the "other"
* one.
*/
physicalCD = describeSharedConglomerate(congDescs, true);
IndexRowGenerator othersIRG = physicalCD.getIndexDescriptor();
/* Let OTHERS denote the set of "other" descriptors which
* share a physical conglomerate with this one. Recall
* that (for now) 1) sharing descriptors must always have
* the same columns referenced in the same order, and
* 2) if a unique descriptor shares a conglomerate with
* a non-unique descriptor, the physical conglomerate
* must itself be unique. So given that, we have four
* possible cases:
*
* 1. "this" is unique, none of OTHERS are unique
* 2. "this" is unique, 1 or more of OTHERS is unique
* 3. "this" is not unique, none of OTHERS are unique
* 4. "this" is not unique, 1 or more of OTHERS is unique
*
* In case 1 "this" conglomerate descriptor must be the
* _only_ one which fully matches the physical conglom.
* In case 4, "this" descriptor does _not_ fully match
* the physical conglomerate. In cases 2 and 3, "this"
* descriptor fully matches the physical conglom, but it
* is NOT the only one to do so--which means we don't need
* to update the physical conglomerate when we drop "this"
* (because OTHERS need the exact same physical conglom).
* The only case that actually requires an "updated"
* conglomerate, then, is case 1, since the physical
* conglomerate for the remaining descriptors no longer
* has a uniqueness requirement.
*/
needNewConglomerate =
(indexRowGenerator.isUnique() && !othersIRG.isUnique()) ||
(indexRowGenerator.isUniqueWithDuplicateNulls() &&
!othersIRG.isUniqueWithDuplicateNulls());
if (needNewConglomerate)
{
/* We have to create a new backing conglomerate
* to correctly represent the remaing (sharing)
* descriptors, so drop the physical conglomerate
* now. The caller of the method can then create
* new conglomerate as/if needed.
*/
dropConglom = true;
}
else
physicalCD = null;
}
if (dropConglom)
{
/* Drop statistics */
dd.dropStatisticsDescriptors(td.getUUID(), getUUID(), tc);
/* Drop the physical conglomerate */
tc.dropConglomerate(getConglomerateNumber());
}
/* Drop the conglomerate descriptor */
dd.dropConglomerateDescriptor(this, tc);
/*
** Remove the conglomerate descriptor from the list hanging off of the
** table descriptor
*/
td.removeConglomerateDescriptor(this);
return physicalCD;
}
Drop this ConglomerateDescriptor when it represents
an index. If this is the last desciptor for
a physical index then the physical index (conglomerate)
and its descriptor will be dropped. |
public String getClassType() {
if (indexable)
{
return Dependable.INDEX;
}
else
{
return Dependable.HEAP;
}
}
|
public String[] getColumnNames() {
return columnNames;
}
Get the column names for this conglomerate descriptor.
This is useful for tracing the optimizer. |
public String getConglomerateName() {
return name;
}
Gets the name of the conglomerate. For heaps, this is null. For
indexes, it is the index name. |
public long getConglomerateNumber() {
return conglomerateNumber;
}
Gets the number for the conglomerate. |
public DependableFinder getDependableFinder() {
return getDependableFinder(StoredFormatIds.CONGLOMERATE_DESCRIPTOR_FINDER_V01_ID);
}
|
public String getDescriptorName() {
return name;
}
|
public String getDescriptorType() {
if (indexable)
return "Index";
else
return "Table";
}
|
public IndexRowGenerator getIndexDescriptor() {
return indexRowGenerator;
}
Gets the index row generator for this conglomerate, null if the
conglomerate is not an index. |
public UUID getObjectID() {
return uuid;
}
|
public String getObjectName() {
if (SanityManager.DEBUG)
{
SanityManager.ASSERT(name != null,
"ConglomerateDescriptor only expected to be provider for indexes");
}
return name;
}
Return the name of this Provider. (Useful for errors.) |
public UUID getSchemaID() {
return schemaID;
}
Gets the UUID for the schema that the conglomerate belongs to. |
public UUID getTableID() {
return tableID;
}
Gets the UUID for the table that the conglomerate belongs to. |
public UUID getUUID() {
return uuid;
}
Gets the UUID String for the conglomerate. |
public boolean isConstraint() {
return forConstraint;
}
Tells whether the conglomerate is an index backing up a constraint. |
public boolean isIndex() {
return indexable;
}
Tells whether the conglomerate can be used as an index. |
public void setColumnNames(String[] columnNames) {
this.columnNames = columnNames;
}
Set the column names for this conglomerate descriptor.
This is useful for tracing the optimizer. |
public void setConglomerateName(String newName) {
name = newName;
}
Set the name of the conglomerate. Used only by rename index. |
public void setConglomerateNumber(long conglomerateNumber) {
this.conglomerateNumber = conglomerateNumber;
}
Set the conglomerate number.
This is useful when swapping conglomerates, like for bulkInsert. |
public String toString() {
if (SanityManager.DEBUG)
{
String keyString = "";
if (indexable && columnNames != null )
{
int[] keyColumns = indexRowGenerator.baseColumnPositions();
keyString = ", key columns = {" + columnNames[keyColumns[0] - 1];
for (int index = 1; index < keyColumns.length; index++)
{
keyString = keyString + ", " + columnNames[keyColumns[index] - 1];
}
keyString = keyString + "}";
}
return "ConglomerateDescriptor: conglomerateNumber = " + conglomerateNumber +
" name = " + name +
" uuid = " + uuid +
" indexable = " + indexable + keyString;
}
else
{
return "";
}
}
Convert the conglomerate descriptor to a String |