DataValueDescriptor[] scratch_template,
DataValueDescriptor[] rowToInsert,
int flag)
throws StandardException
{
TransactionManager split_xact = null;
OpenBTree split_open_btree = null;
ControlRow root = null;
// Get an internal transaction to be used for the split.
split_xact = this.init_open_user_scans.getInternalTransaction();
// open the btree again so that actions on it take place in the
// split_xact, don't get any locks in this transaction.
if (SanityManager.DEBUG)
{
if (((getOpenMode() & ContainerHandle.MODE_FORUPDATE) !=
ContainerHandle.MODE_FORUPDATE))
{
SanityManager.THROWASSERT(
"Container not opened with update should not cause split");
}
}
boolean do_split = true;
if (attempt_to_reclaim_deleted_rows)
{
// Get lock on base table.
ConglomerateController base_cc = null;
try
{
base_cc =
this.getConglomerate().lockTable(
split_xact,
(ContainerHandle.MODE_FORUPDATE |
ContainerHandle.MODE_LOCK_NOWAIT),
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_REPEATABLE_READ);
}
catch (StandardException se)
{
// any error just don't try to reclaim deleted rows. The
// expected error is that we can't get the lock, which the
// current interface throws as a containerNotFound exception.
}
if (base_cc != null)
{
// we got IX lock on the base table, so can try reclaim space.
// We can only reclaim space by opening the btree in row lock
// mode. Table level lock row recovery is hard as we can't
// determine if the deleted rows we encounter have been
// deleted by our parent caller and have been committed or
// not. We will have to get those rows offline.
split_open_btree = new OpenBTree();
split_open_btree.init(
this.init_open_user_scans,
split_xact,
null, // open the container.
split_xact.getRawStoreXact(),
false,
(ContainerHandle.MODE_FORUPDATE |
ContainerHandle.MODE_LOCK_NOWAIT),
TransactionManager.MODE_RECORD,
this.getConglomerate().getBtreeLockingPolicy(
split_xact.getRawStoreXact(),
TransactionController.MODE_RECORD,
LockingPolicy.MODE_RECORD,
TransactionController.ISOLATION_REPEATABLE_READ,
(ConglomerateController) base_cc,
split_open_btree),
this.getConglomerate(),
(LogicalUndo) null,
(DynamicCompiledOpenConglomInfo) null);
// don't split if we reclaim any rows.
do_split = !reclaim_deleted_rows(split_open_btree, leaf_pageno);
// on return if !do_split then the latch on leaf_pageno is held
// and will be released by the committing or aborting the
// transaction. If a purge has been done, no other action on
// the page should be attempted (ie. a split) before committing
// the purges.
split_open_btree.close();
}
}
long new_leaf_pageno = leaf_pageno;
if (do_split)
{
// no space was reclaimed from deleted rows, so do split to allow
// space for a subsequent insert.
split_open_btree = new OpenBTree();
split_open_btree.init(
this.init_open_user_scans,
split_xact,
null, // open the container.
split_xact.getRawStoreXact(),
false,
getOpenMode(), // use same mode this controller
// was opened with
TransactionManager.MODE_NONE,
this.getConglomerate().getBtreeLockingPolicy(
split_xact.getRawStoreXact(),
this.init_lock_level,
LockingPolicy.MODE_RECORD,
TransactionController.ISOLATION_REPEATABLE_READ,
(ConglomerateController) null, // no base row locks during split
split_open_btree),
this.getConglomerate(),
(LogicalUndo) null,
(DynamicCompiledOpenConglomInfo) null);
// Get the root page back, and perform a split following the
// to-be-inserted key. The split releases the root page latch.
root = ControlRow.get(split_open_btree, BTree.ROOTPAGEID);
if (SanityManager.DEBUG)
SanityManager.ASSERT(root.page.isLatched());
new_leaf_pageno =
root.splitFor(
split_open_btree, scratch_template,
null, rowToInsert, flag);
split_open_btree.close();
}
split_xact.commit();
split_xact.destroy();
return(new_leaf_pageno);
}