use of org.apache.derby.iapi.store.access.TransactionController in project derby by apache.
the class IndexStatisticsDaemonImpl method processingLoop.
/**
* Main processing loop which will compute statistics until the queue
* of scheduled work units has been drained.
*/
private void processingLoop() {
// If we don't have a connection to the database, create one.
if (daemonLCC == null) {
try {
daemonLCC = db.setupConnection(ctxMgr, dbOwner, null, databaseName);
// Initialize the lcc/transaction.
// TODO: Would be nice to name the transaction.
daemonLCC.setIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED);
// Don't wait for any locks.
daemonLCC.getTransactionExecute().setNoLockWait(true);
} catch (StandardException se) {
log(AS_BACKGROUND_TASK, null, se, "failed to initialize index statistics updater");
return;
}
}
TransactionController tc = null;
try {
tc = daemonLCC.getTransactionExecute();
trace(0, "worker thread started (xid=" + tc.getTransactionIdString() + ")");
TableDescriptor td = null;
long start = 0;
while (true) {
synchronized (queue) {
if (daemonDisabled) {
// Clean the lcc and exit.
try {
tc.destroy();
} catch (ShutdownException se) {
// Ignore
}
tc = null;
daemonLCC = null;
queue.clear();
trace(1, "daemon disabled");
break;
}
if (queue.isEmpty()) {
trace(1, "queue empty");
break;
}
td = queue.get(0);
}
try {
start = System.currentTimeMillis();
generateStatistics(daemonLCC, td);
wuProcessed++;
// Reset consecutive error counter.
errorsConsecutive = 0;
log(AS_BACKGROUND_TASK, td, "generation complete (" + ((System.currentTimeMillis() - start)) + " ms)");
} catch (StandardException se) {
errorsConsecutive++;
// For less severe errors, rollback tx to clean up.
if (!handleFatalErrors(ctxMgr, se)) {
boolean handled = handleExpectedErrors(td, se);
if (!handled) {
handled = handleUnexpectedErrors(td, se);
}
daemonLCC.internalRollback();
if (SanityManager.DEBUG) {
SanityManager.ASSERT(handled);
}
}
} finally {
// Whatever happened, discard the unit of work.
synchronized (queue) {
// Queue may have been cleared due to shutdown.
if (!queue.isEmpty()) {
queue.remove(0);
}
}
// Create an exception to force logging of the message.
if (errorsConsecutive >= 50) {
log(AS_BACKGROUND_TASK, null, new IllegalStateException("degraded state"), "shutting down daemon, " + errorsConsecutive + " consecutive errors seen");
stop();
}
}
}
} catch (StandardException se) {
log(AS_BACKGROUND_TASK, null, se, "thread died");
// Do nothing, just let the thread die.
} finally {
synchronized (queue) {
runningThread = null;
}
if (daemonLCC != null && !daemonLCC.isTransactionPristine()) {
if (SanityManager.DEBUG) {
SanityManager.THROWASSERT("transaction not pristine");
}
log(AS_BACKGROUND_TASK, null, "transaction not pristine - forcing rollback");
try {
daemonLCC.internalRollback();
} catch (StandardException se) {
// Log, then continue.
log(AS_BACKGROUND_TASK, null, se, "forced rollback failed");
}
}
}
}
use of org.apache.derby.iapi.store.access.TransactionController in project derby by apache.
the class IndexStatisticsDaemonImpl method updateIndexStatsMinion.
/**
* Updates the index statistics for the given table and the specified
* indexes.
* <p>
* <strong>API note</strong>: Using {@code null} to update the statistics
* for all conglomerates is preferred over explicitly passing an array with
* all the conglomerates for the table. Doing so allows for some
* optimizations, and will cause a disposable statistics check to be
* performed.
*
* @param lcc language connection context used to perform the work
* @param td the table to update index stats for
* @param cds the conglomerates to update statistics for (non-index
* conglomerates will be ignored), {@code null} means all indexes
* @param asBackgroundTask whether the updates are done automatically as
* part of a background task or if explicitly invoked by the user
* @throws StandardException if something goes wrong
*/
private void updateIndexStatsMinion(LanguageConnectionContext lcc, TableDescriptor td, ConglomerateDescriptor[] cds, boolean asBackgroundTask) throws StandardException {
// can only properly identify disposable stats if cds == null,
// which means we are processing all indexes on the conglomerate.
final boolean identifyDisposableStats = (cds == null);
// Fetch descriptors if we're updating statistics for all indexes.
if (cds == null) {
cds = td.getConglomerateDescriptors();
}
// Extract/derive information from the table descriptor
long[] conglomerateNumber = new long[cds.length];
ExecIndexRow[] indexRow = new ExecIndexRow[cds.length];
TransactionController tc = lcc.getTransactionExecute();
ConglomerateController heapCC = tc.openConglomerate(td.getHeapConglomerateId(), false, 0, TransactionController.MODE_RECORD, asBackgroundTask ? TransactionController.ISOLATION_READ_UNCOMMITTED : TransactionController.ISOLATION_REPEATABLE_READ);
// create a list of indexes that should have statistics, by looking
// at all indexes on the conglomerate, and conditionally skipping
// unique single column indexes. This set is the "non disposable
// stat list".
UUID[] non_disposable_objectUUID = new UUID[cds.length];
try {
for (int i = 0; i < cds.length; i++) {
// Skip non-index conglomerates
if (!cds[i].isIndex()) {
conglomerateNumber[i] = -1;
continue;
}
IndexRowGenerator irg = cds[i].getIndexDescriptor();
// or we are running in soft-upgrade-mode on a pre 10.9 db.
if (skipDisposableStats) {
if (irg.isUnique() && irg.numberOfOrderedColumns() == 1) {
conglomerateNumber[i] = -1;
continue;
}
}
// at this point have found a stat for an existing
// index which is not a single column unique index, add it
// to the list of "non disposable stats"
conglomerateNumber[i] = cds[i].getConglomerateNumber();
non_disposable_objectUUID[i] = cds[i].getUUID();
indexRow[i] = irg.getNullIndexRow(td.getColumnDescriptorList(), heapCC.newRowLocationTemplate());
}
} finally {
heapCC.close();
}
if (identifyDisposableStats) {
// Note this loop is not controlled by the skipDisposableStats
// flag. The above loop controls if we drop single column unique
// index stats or not. In all cases we are going to drop
// stats with no associated index (orphaned stats).
List<StatisticsDescriptor> existingStats = td.getStatistics();
StatisticsDescriptor[] stats = (StatisticsDescriptor[]) existingStats.toArray(new StatisticsDescriptor[existingStats.size()]);
// those entries that don't have a matching conglomerate in the
for (int si = 0; si < stats.length; si++) {
UUID referencedIndex = stats[si].getReferenceID();
boolean isValid = false;
for (int ci = 0; ci < conglomerateNumber.length; ci++) {
if (referencedIndex.equals(non_disposable_objectUUID[ci])) {
isValid = true;
break;
}
}
// mechanism in case of another bug like DERBY-5681 in Derby.
if (!isValid) {
String msg = "dropping disposable statistics entry " + stats[si].getUUID() + " for index " + stats[si].getReferenceID() + " (cols=" + stats[si].getColumnCount() + ")";
logAlways(td, null, msg);
trace(1, msg + " on table " + stats[si].getTableUUID());
DataDictionary dd = lcc.getDataDictionary();
if (!lcc.dataDictionaryInWriteMode()) {
dd.startWriting(lcc);
}
dd.dropStatisticsDescriptors(td.getUUID(), stats[si].getReferenceID(), tc);
if (asBackgroundTask) {
lcc.internalCommit(true);
}
}
}
}
// [x][0] = conglomerate number, [x][1] = start time, [x][2] = stop time
long[][] scanTimes = new long[conglomerateNumber.length][3];
int sci = 0;
for (int indexNumber = 0; indexNumber < conglomerateNumber.length; indexNumber++) {
if (conglomerateNumber[indexNumber] == -1)
continue;
// Check if daemon has been disabled.
if (asBackgroundTask) {
if (isShuttingDown()) {
break;
}
}
scanTimes[sci][0] = conglomerateNumber[indexNumber];
scanTimes[sci][1] = System.currentTimeMillis();
// Subtract one for the RowLocation added for indexes.
int numCols = indexRow[indexNumber].nColumns() - 1;
long[] cardinality = new long[numCols];
KeyComparator cmp = new KeyComparator(indexRow[indexNumber]);
/* Read uncommitted, with record locking. Actually CS store may
not hold record locks */
GroupFetchScanController gsc = tc.openGroupFetchScan(conglomerateNumber[indexNumber], // hold
false, 0, // locking
TransactionController.MODE_RECORD, TransactionController.ISOLATION_READ_UNCOMMITTED, // scancolumnlist-- want everything.
null, // startkeyvalue-- start from the beginning.
null, 0, // qualifiers, none!
null, // stopkeyvalue,
null, 0);
try {
int rowsFetched = 0;
boolean giving_up_on_shutdown = false;
while ((rowsFetched = cmp.fetchRows(gsc)) > 0) {
// I/O that is processed as a convenient point.
if (asBackgroundTask) {
if (isShuttingDown()) {
giving_up_on_shutdown = true;
break;
}
}
for (int i = 0; i < rowsFetched; i++) {
int whichPositionChanged = cmp.compareWithPrevKey(i);
if (whichPositionChanged >= 0) {
for (int j = whichPositionChanged; j < numCols; j++) cardinality[j]++;
}
}
}
if (giving_up_on_shutdown)
break;
gsc.setEstimatedRowCount(cmp.getRowCount());
} finally // try
{
gsc.close();
gsc = null;
}
scanTimes[sci++][2] = System.currentTimeMillis();
// We have scanned the indexes, so let's give this a few attempts
// before giving up.
int retries = 0;
while (true) {
try {
writeUpdatedStats(lcc, td, non_disposable_objectUUID[indexNumber], cmp.getRowCount(), cardinality, asBackgroundTask);
break;
} catch (StandardException se) {
retries++;
if (se.isLockTimeout() && retries < 3) {
trace(2, "lock timeout when writing stats, retrying");
sleep(100 * retries);
} else {
// o too many lock timeouts
throw se;
}
}
}
}
log(asBackgroundTask, td, fmtScanTimes(scanTimes));
}
use of org.apache.derby.iapi.store.access.TransactionController in project derby by apache.
the class Deadlock method buildException.
/**
* Build an exception that describes a deadlock.
*
* @param factory the lock factory requesting the exception
* @param data an array with information about who's involved in
* a deadlock (as returned by {@link #handle})
* @return a deadlock exception
*/
static StandardException buildException(AbstractPool factory, Object[] data) {
Stack chain = (Stack) data[0];
Dictionary waiters = (Dictionary) data[1];
LanguageConnectionContext lcc = (LanguageConnectionContext) getContext(LanguageConnectionContext.CONTEXT_ID);
TableNameInfo tabInfo = null;
TransactionInfo[] tt = null;
TransactionController tc = null;
if (lcc != null) {
try {
tc = lcc.getTransactionExecute();
tabInfo = new TableNameInfo(lcc, false);
tt = tc.getAccessManager().getTransactionInfo();
} catch (StandardException se) {
// just don't get any table info.
}
}
StringBuffer sb = new StringBuffer(200);
Hashtable<String, Object> attributes = new Hashtable<String, Object>(17);
String victimXID = null;
for (int i = 0; i < chain.size(); i++) {
Object space = chain.elementAt(i);
if (space instanceof List) {
List grants = (List) space;
if (grants.size() != 0) {
sb.append(" Granted XID : ");
for (int j = 0; j < grants.size(); j++) {
if (j != 0)
sb.append(", ");
Lock gl = (Lock) grants.get(j);
sb.append("{");
sb.append(gl.getCompatabilitySpace().getOwner());
sb.append(", ");
sb.append(gl.getQualifier());
sb.append("} ");
}
sb.append('\n');
}
continue;
}
// Information about the lock we are waiting on
// TYPE |TABLENAME |LOCKNAME
Lock lock = ((Lock) waiters.get(space));
// see if this lockable object wants to participate
lock.getLockable().lockAttributes(VirtualLockTable.ALL, attributes);
addInfo(sb, "Lock : ", attributes.get(VirtualLockTable.LOCKTYPE));
if (tabInfo != null) {
Long conglomId = (Long) attributes.get(VirtualLockTable.CONGLOMID);
if (conglomId == null) {
Long containerId = (Long) attributes.get(VirtualLockTable.CONTAINERID);
try {
conglomId = tc.findConglomid(containerId.longValue());
} catch (StandardException se) {
}
}
addInfo(sb, ", ", tabInfo.getTableName(conglomId));
}
addInfo(sb, ", ", attributes.get(VirtualLockTable.LOCKNAME));
sb.append('\n');
String xid = String.valueOf(lock.getCompatabilitySpace().getOwner());
if (i == 0)
victimXID = xid;
addInfo(sb, " Waiting XID : {", xid);
addInfo(sb, ", ", lock.getQualifier());
sb.append("} ");
if (tt != null) {
for (int tti = tt.length - 1; tti >= 0; tti--) {
TransactionInfo ti = tt[tti];
// ti.getTransactionIdString() or ti can return null.
if (ti != null) {
String idString = ti.getTransactionIdString();
if (idString != null && idString.equals(xid)) {
addInfo(sb, ", ", ti.getUsernameString());
addInfo(sb, ", ", ti.getStatementTextString());
break;
}
}
}
}
sb.append('\n');
attributes.clear();
}
StandardException se = StandardException.newException(SQLState.DEADLOCK, sb.toString(), victimXID);
se.setReport(factory.deadlockMonitor);
return se;
}
use of org.apache.derby.iapi.store.access.TransactionController in project derby by apache.
the class DeleteNode method makeConstantAction.
/**
* Compile constants that Execution will use
*
* @exception StandardException Thrown on failure
*/
@Override
public ConstantAction makeConstantAction() throws StandardException {
/* Different constant actions for base tables and updatable VTIs */
if (targetTableDescriptor != null) {
// Base table
int lckMode = resultSet.updateTargetLockMode();
long heapConglomId = targetTableDescriptor.getHeapConglomerateId();
TransactionController tc = getLanguageConnectionContext().getTransactionCompile();
StaticCompiledOpenConglomInfo[] indexSCOCIs = new StaticCompiledOpenConglomInfo[indexConglomerateNumbers.length];
for (int index = 0; index < indexSCOCIs.length; index++) {
indexSCOCIs[index] = tc.getStaticCompiledConglomInfo(indexConglomerateNumbers[index]);
}
/*
** Do table locking if the table's lock granularity is
** set to table.
*/
if (targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY) {
lckMode = TransactionController.MODE_TABLE;
}
ResultDescription resultDescription = null;
if (isDependentTable) {
// triggers need the result description ,
// dependent tables don't have a source from generation time
// to get the result description
resultDescription = makeResultDescription();
}
return getGenericConstantActionFactory().getDeleteConstantAction(heapConglomId, targetTableDescriptor.getTableType(), tc.getStaticCompiledConglomInfo(heapConglomId), indicesToMaintain, indexConglomerateNumbers, indexSCOCIs, deferred, false, targetTableDescriptor.getUUID(), lckMode, null, null, null, 0, null, null, resultDescription, getFKInfo(), getTriggerInfo(), (readColsBitSet == null) ? (FormatableBitSet) null : new FormatableBitSet(readColsBitSet), getReadColMap(targetTableDescriptor.getNumberOfColumns(), readColsBitSet), resultColumnList.getStreamStorableColIds(targetTableDescriptor.getNumberOfColumns()), (readColsBitSet == null) ? targetTableDescriptor.getNumberOfColumns() : readColsBitSet.getNumBitsSet(), (UUID) null, resultSet.isOneRowResultSet(), dependentConstantActions, inMatchingClause());
} else {
/* Return constant action for VTI
* NOTE: ConstantAction responsible for preserving instantiated
* VTIs for in-memory queries and for only preserving VTIs
* that implement Serializable for SPSs.
*/
return getGenericConstantActionFactory().getUpdatableVTIConstantAction(DeferModification.DELETE_STATEMENT, deferred);
}
}
use of org.apache.derby.iapi.store.access.TransactionController in project derby by apache.
the class CreateTableConstantAction method executeConstantAction.
// INTERFACE METHODS
/**
* This is the guts of the Execution-time logic for CREATE TABLE.
*
* @see ConstantAction#executeConstantAction
*
* @exception StandardException Thrown on failure
*/
public void executeConstantAction(Activation activation) throws StandardException {
TableDescriptor td;
UUID toid;
SchemaDescriptor schemaDescriptor;
ColumnDescriptor columnDescriptor;
ExecRow template;
LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
DataDictionary dd = lcc.getDataDictionary();
DependencyManager dm = dd.getDependencyManager();
TransactionController tc = lcc.getTransactionExecute();
/* Mark the activation as being for create table */
activation.setForCreateTable();
// setup for create conglomerate call:
// o create row template to tell the store what type of rows this
// table holds.
// o create array of collation id's to tell collation id of each
// column in table.
template = RowUtil.getEmptyValueRow(columnInfo.length, lcc);
int[] collation_ids = new int[columnInfo.length];
for (int ix = 0; ix < columnInfo.length; ix++) {
ColumnInfo col_info = columnInfo[ix];
if (col_info.defaultValue != null) {
/* If there is a default value, use it, otherwise use null */
template.setColumn(ix + 1, col_info.defaultValue);
} else {
template.setColumn(ix + 1, col_info.dataType.getNull());
}
// get collation info for each column.
collation_ids[ix] = col_info.dataType.getCollationType();
}
/* create the conglomerate to hold the table's rows
* RESOLVE - If we ever have a conglomerate creator
* that lets us specify the conglomerate number then
* we will need to handle it here.
*/
long conglomId = tc.createConglomerate(// we're requesting a heap conglomerate
"heap", // row template
template.getRowArray(), // column sort order - not required for heap
null, collation_ids, // properties
properties, tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE ? (TransactionController.IS_TEMPORARY | TransactionController.IS_KEPT) : TransactionController.IS_DEFAULT);
/*
** Inform the data dictionary that we are about to write to it.
** There are several calls to data dictionary "get" methods here
** that might be done in "read" mode in the data dictionary, but
** it seemed safer to do this whole operation in "write" mode.
**
** We tell the data dictionary we're done writing at the end of
** the transaction.
*/
if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
dd.startWriting(lcc);
SchemaDescriptor sd;
if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
sd = dd.getSchemaDescriptor(schemaName, tc, true);
else
sd = DDLConstantAction.getSchemaDescriptorForCreate(dd, activation, schemaName);
//
// Create a new table descriptor.
//
DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
td = ddg.newTableDescriptor(tableName, sd, tableType, lockGranularity);
dd.addDescriptor(td, sd, DataDictionary.SYSTABLES_CATALOG_NUM, false, tc);
} else {
td = ddg.newTableDescriptor(tableName, sd, tableType, onCommitDeleteRows, onRollbackDeleteRows);
td.setUUID(dd.getUUIDFactory().createUUID());
}
toid = td.getUUID();
// Save the TableDescriptor off in the Activation
activation.setDDLTableDescriptor(td);
/* NOTE: We must write the columns out to the system
* tables before any of the conglomerates, including
* the heap, since we read the columns before the
* conglomerates when building a TableDescriptor.
* This will hopefully reduce the probability of
* a deadlock involving those system tables.
*/
// for each column, stuff system.column
int index = 1;
ColumnDescriptor[] cdlArray = new ColumnDescriptor[columnInfo.length];
for (int ix = 0; ix < columnInfo.length; ix++) {
UUID defaultUUID = columnInfo[ix].newDefaultUUID;
/* Generate a UUID for the default, if one exists
* and there is no default id yet.
*/
if (columnInfo[ix].defaultInfo != null && defaultUUID == null) {
defaultUUID = dd.getUUIDFactory().createUUID();
}
if (// dealing with autoinc column
columnInfo[ix].autoincInc != 0) {
columnDescriptor = new ColumnDescriptor(columnInfo[ix].name, index++, columnInfo[ix].dataType, columnInfo[ix].defaultValue, columnInfo[ix].defaultInfo, td, defaultUUID, columnInfo[ix].autoincStart, columnInfo[ix].autoincInc, columnInfo[ix].autoinc_create_or_modify_Start_Increment, columnInfo[ix].autoincCycle);
//
if (dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, null)) {
CreateSequenceConstantAction csca = makeCSCA(columnInfo[ix], TableDescriptor.makeSequenceName(toid));
csca.executeConstantAction(activation);
}
} else {
columnDescriptor = new ColumnDescriptor(columnInfo[ix].name, index++, columnInfo[ix].dataType, columnInfo[ix].defaultValue, columnInfo[ix].defaultInfo, td, defaultUUID, columnInfo[ix].autoincStart, columnInfo[ix].autoincInc, columnInfo[ix].autoincCycle);
}
cdlArray[ix] = columnDescriptor;
}
if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
dd.addDescriptorArray(cdlArray, td, DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);
}
// now add the column descriptors to the table.
ColumnDescriptorList cdl = td.getColumnDescriptorList();
for (int i = 0; i < cdlArray.length; i++) cdl.add(cdlArray[i]);
//
// Create a conglomerate desciptor with the conglomId filled in and
// add it.
//
// RESOLVE: Get information from the conglomerate descriptor which
// was provided.
//
ConglomerateDescriptor cgd = ddg.newConglomerateDescriptor(conglomId, null, false, null, false, null, toid, sd.getUUID());
if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
dd.addDescriptor(cgd, sd, DataDictionary.SYSCONGLOMERATES_CATALOG_NUM, false, tc);
}
// add the newly added conglomerate to the table descriptor
ConglomerateDescriptorList conglomList = td.getConglomerateDescriptorList();
conglomList.add(cgd);
/* Create any constraints */
if (constraintActions != null) {
/*
** Do everything but FK constraints first,
** then FK constraints on 2nd pass.
*/
for (int conIndex = 0; conIndex < constraintActions.length; conIndex++) {
// skip fks
if (!constraintActions[conIndex].isForeignKeyConstraint()) {
constraintActions[conIndex].executeConstantAction(activation);
}
}
for (int conIndex = 0; conIndex < constraintActions.length; conIndex++) {
// only foreign keys
if (constraintActions[conIndex].isForeignKeyConstraint()) {
constraintActions[conIndex].executeConstantAction(activation);
}
}
}
//
for (int ix = 0; ix < columnInfo.length; ix++) {
addColumnDependencies(lcc, dd, td, columnInfo[ix]);
}
//
// The table itself can depend on the user defined types of its columns.
//
adjustUDTDependencies(lcc, dd, td, columnInfo, false);
if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
lcc.addDeclaredGlobalTempTable(td);
}
// Indicate that the CREATE TABLE statement itself depends on the
// table it is creating. Normally such statement dependencies are
// added during compilation, but here we have a bootstrapping issue
// because the table doesn't exist until the CREATE TABLE statement
// has been executed, so we had to defer the creation of this
// dependency until now. (DERBY-4479)
dd.getDependencyManager().addDependency(activation.getPreparedStatement(), td, lcc.getContextManager());
}
Aggregations