use of org.apache.derby.iapi.store.raw.Page in project derby by apache.
the class BTreeController method reclaim_deleted_rows.
/*
** private Methods of BTreeController
*/
/**
* Attempt to reclaim committed deleted rows from the page.
* <p>
* Get exclusive latch on page, and then loop backward through
* page searching for deleted rows which are committed. The routine
* assumes that it is called from a transaction which cannot have
* deleted any rows on the page. For each deleted row on the page
* it attempts to get an exclusive lock on the deleted row, NOWAIT.
* If it succeeds, and since this row did not delete the row then the
* row must have been deleted by a transaction which has committed, so
* it is safe to purge the row. It then purges the row from the page.
* <p>
* Note that this routine may remove all rows from the page, it will not
* attempt a merge in this situation. This is because this routine is
* called from split which is attempting an insert on the given page, so
* it would be a waste to merge the page only to split it again to allow
* the insert of the row causing the split.
*
* @return true if at least one row was purged. If true, then the routine
* will leave the page latched, and the caller will release
* the latch by committing or aborting the transaction. The
* latch must be held to end transaction to insure space on
* the page remains available for a undo of the purge.
*
* @param open_btree The already open btree to use to get latch on page.
* @param pageno The page number of the leaf to attempt the reclaim on.
*
* @exception StandardException Standard exception policy.
*/
private boolean reclaim_deleted_rows(OpenBTree open_btree, long pageno) throws StandardException {
boolean purged_at_least_one_row = false;
ControlRow controlRow = null;
try {
if ((controlRow = ControlRow.get(open_btree, pageno)) == null)
return (false);
LeafControlRow leaf = (LeafControlRow) controlRow;
BTreeLockingPolicy btree_locking_policy = open_btree.getLockingPolicy();
// The number records that can be reclaimed is:
// total recs - control row - recs_not_deleted
int num_possible_commit_delete = leaf.page.recordCount() - 1 - leaf.page.nonDeletedRecordCount();
if (num_possible_commit_delete > 0) {
Page page = leaf.page;
// RowLocation column is in last column of template.
FetchDescriptor lock_fetch_desc = RowUtil.getFetchDescriptorConstant(scratch_template.length - 1);
// have already looked at).
for (int slot_no = page.recordCount() - 1; slot_no > 0; slot_no--) {
if (page.isDeletedAtSlot(slot_no)) {
// safe to purge it.
if (btree_locking_policy.lockScanCommittedDeletedRow(open_btree, leaf, scratch_template, lock_fetch_desc, slot_no)) {
// the row is a committed deleted row, purge it.
page.purgeAtSlot(slot_no, 1, true);
purged_at_least_one_row = true;
}
}
}
}
} catch (java.lang.ClassCastException cce) {
// because we give up the latch on the leaf before entering this
// routine, the page might change from a leaf to branch. If that
// happens this routine will get a ClassCastException, and we
// just give up trying to reclaim space.
} finally {
if (controlRow != null) {
if (purged_at_least_one_row) {
// Set a hint in the page that scans positioned on it
// need to reposition because rows have disappeared from
// the page. If at least one row has been purged, then
// do not release the latch. Purge requires latch to
// be held until commit, where it will be released after
// the commit log record has been logged.
controlRow.page.setRepositionNeeded();
} else {
// Ok to release latch if no purging has happened.
controlRow.release();
}
}
}
return (purged_at_least_one_row);
}
use of org.apache.derby.iapi.store.raw.Page in project derby by apache.
the class DeleteOperation method restoreLoggedRow.
/*
* LogicalUndoable methods
*/
/**
* Restore the row stored in the optional data of the log record.
*
* @exception IOException error reading from log stream
* @exception StandardException Standard Derby error policy
*/
public void restoreLoggedRow(Object[] row, LimitObjectInput in) throws StandardException, IOException {
Page p = null;
try {
// the optional data is written by the page in the same format it
// stores record on the page,
// only a page knows how to restore a logged row back to a storable row
// first get the page where the insert went even though the row may no
// longer be there
p = getContainer().getPage(getPageId().getPageNumber());
((BasePage) p).restoreRecordFromStream(in, row);
} finally {
if (p != null) {
p.unlatch();
p = null;
}
}
}
use of org.apache.derby.iapi.store.raw.Page in project derby by apache.
the class D_DiagnosticUtil method diag_dump_page.
/**
* Dump raw contents of a page.
* <p>
* A utility routine that can be called from an ij session that will
* dump the raw contents of a page, in the raw store dump format.
*
* @param db_name name of the database
* @param segmentid segmentid of the table (usually 0)
* @param containerid containerid of the table (not conglomid)
* @param pagenumber pagenumber of page to dump.
*/
public static void diag_dump_page(String db_name, long segmentid, long containerid, long pagenumber) {
Transaction xact = null;
try {
Object module = getModuleFromDbName(db_name);
RawStoreFactory store_module = (RawStoreFactory) findServiceModule(module, RawStoreFactory.MODULE);
xact = store_module.startInternalTransaction(FileContainer.getContextService().getCurrentContextManager());
ContainerKey id = new ContainerKey(segmentid, containerid);
ContainerHandle container = xact.openContainer(id, ContainerHandle.MODE_READONLY);
Page page = container.getPage(pagenumber);
if (page != null) {
System.out.println(page.toString());
page.unlatch();
} else {
System.out.println("page " + pagenumber + " not found");
}
xact.abort();
xact.close();
xact = null;
} catch (StandardException se) {
se.printStackTrace();
} finally {
if (xact != null) {
try {
xact.abort();
xact.close();
} catch (StandardException se) {
}
}
}
}
use of org.apache.derby.iapi.store.raw.Page in project derby by apache.
the class ReclaimSpaceHelper method reclaimSpace.
/**
* Reclaim space based on work.
*/
public static int reclaimSpace(BaseDataFileFactory dataFactory, RawTransaction tran, ReclaimSpace work) throws StandardException {
if (work.reclaimWhat() == ReclaimSpace.CONTAINER)
return reclaimContainer(dataFactory, tran, work);
// Else, not reclaiming container. Get a no-wait shared lock on the
// container regardless of how the user transaction had the
// container opened.
LockingPolicy container_rlock = tran.newLockingPolicy(LockingPolicy.MODE_RECORD, TransactionController.ISOLATION_SERIALIZABLE, true);
if (SanityManager.DEBUG)
SanityManager.ASSERT(container_rlock != null);
ContainerHandle containerHdl = openContainerNW(tran, container_rlock, work.getContainerId());
if (containerHdl == null) {
tran.abort();
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON(DaemonService.DaemonTrace)) {
SanityManager.DEBUG(DaemonService.DaemonTrace, " aborted " + work + " because container is locked or dropped");
}
}
if (// retry this for serveral times
work.incrAttempts() < 3) // it is however, unlikely that three tries will be
// enough because there is no delay between retries.
// See DERBY-4059 and DERBY-4055 for details.
{
return Serviceable.REQUEUE;
} else {
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON(DaemonService.DaemonTrace)) {
SanityManager.DEBUG(DaemonService.DaemonTrace, " gave up after 3 tries to get container lock " + work);
}
}
return Serviceable.DONE;
}
}
if (work.reclaimWhat() == ReclaimSpace.PAGE) {
// Reclaiming a page - called by undo of insert which purged the
// last row off an overflow page. It is safe to reclaim the page
// without first locking the head row because unlike post commit
// work, this is post abort work. Abort is guarenteed to happen
// and to happen only once, if at all.
Page p = containerHdl.getPageNoWait(work.getPageId().getPageNumber());
if (p != null)
containerHdl.removePage(p);
tran.commit();
return Serviceable.DONE;
}
// We are reclaiming row space or long column.
// First get an xlock on the head row piece.
RecordHandle headRecord = work.getHeadRowHandle();
if (!container_rlock.lockRecordForWrite(tran, headRecord, false, /* not insert */
false)) {
// cannot get the row lock, retry
tran.abort();
if (work.incrAttempts() < 3) {
return Serviceable.REQUEUE;
} else {
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON(DaemonService.DaemonTrace)) {
SanityManager.DEBUG(DaemonService.DaemonTrace, " gave up after 3 tries to get row lock " + work);
}
}
return Serviceable.DONE;
}
}
if (work.reclaimWhat() == ReclaimSpace.ROW_RESERVE) {
// This row may benefit from compaction.
containerHdl.compactRecord(headRecord);
// This work is being done - post commit, there is no user
// transaction that depends on the commit being sync'd. It is safe
// to commitNoSync() This do as one of 2 things will happen:
//
// 1) if any data page associated with this transaction is
// moved from cache to disk, then the transaction log
// must be sync'd to the log record for that change and
// all log records including the commit of this xact must
// be sync'd before returning.
//
// 2) if the data page is never written then the log record
// for the commit may never be written, and the xact will
// never make to disk. This is ok as no subsequent action
// depends on this operation being committed.
//
tran.commitNoSync(Transaction.RELEASE_LOCKS);
return Serviceable.DONE;
} else {
if (SanityManager.DEBUG)
SanityManager.ASSERT(work.reclaimWhat() == ReclaimSpace.COLUMN_CHAIN);
// Reclaiming a long column chain due to update. The long column
// chain being reclaimed is the before image of the update
// operation.
//
long headPageId = ((PageKey) headRecord.getPageId()).getPageNumber();
// DERBY-4050 - we wait for the page so we don't have to retry.
// prior to the 4050 fix, we called getPageNoWait and just
// retried 3 times. This left unreclaimed space if we were
// not successful after three tries.
StoredPage headRowPage = (StoredPage) containerHdl.getPage(headPageId);
if (headRowPage == null) {
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON(DaemonService.DaemonTrace)) {
SanityManager.DEBUG(DaemonService.DaemonTrace, "gave up because hadRowPage was null" + work);
}
}
tran.abort();
return Serviceable.DONE;
}
try {
headRowPage.removeOrphanedColumnChain(work, containerHdl);
} finally {
headRowPage.unlatch();
}
// This work is being done - post commit, there is no user
// transaction that depends on the commit being sync'd. It is safe
// to commitNoSync() This do as one of 2 things will happen:
//
// 1) if any data page associated with this transaction is
// moved from cache to disk, then the transaction log
// must be sync'd to the log record for that change and
// all log records including the commit of this xact must
// be sync'd before returning.
//
// 2) if the data page is never written then the log record
// for the commit may never be written, and the xact will
// never make to disk. This is ok as no subsequent action
// depends on this operation being committed.
//
tran.commitNoSync(Transaction.RELEASE_LOCKS);
return Serviceable.DONE;
}
}
use of org.apache.derby.iapi.store.raw.Page in project derby by apache.
the class BaseDataFileFactory method addContainer.
/**
* Add a container with a specified page size to a segment.
* @exception StandardException Standard Derby error policy
*/
public long addContainer(RawTransaction t, long segmentId, long input_containerid, int mode, Properties tableProperties, int temporaryFlag) throws StandardException {
if (SanityManager.DEBUG) {
if ((mode & ContainerHandle.MODE_CREATE_UNLOGGED) != 0)
SanityManager.ASSERT((mode & ContainerHandle.MODE_UNLOGGED) != 0, "cannot have CREATE_UNLOGGED set but UNLOGGED not set");
}
// If client has provided a containerid then use it, else use the
// internally generated one from getNextId().
long containerId = ((input_containerid != ContainerHandle.DEFAULT_ASSIGN_ID) ? input_containerid : getNextId());
ContainerKey identity = new ContainerKey(segmentId, containerId);
boolean tmpContainer = (segmentId == ContainerHandle.TEMPORARY_SEGMENT);
ContainerHandle ch = null;
LockingPolicy cl = null;
if (!tmpContainer) {
if (isReadOnly()) {
throw StandardException.newException(SQLState.DATA_CONTAINER_READ_ONLY);
}
cl = t.newLockingPolicy(LockingPolicy.MODE_CONTAINER, TransactionController.ISOLATION_SERIALIZABLE, true);
if (SanityManager.DEBUG)
SanityManager.ASSERT(cl != null);
ch = t.openContainer(identity, cl, (ContainerHandle.MODE_FORUPDATE | ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY));
}
FileContainer container = (FileContainer) containerCache.create(identity, tableProperties);
// create the first alloc page and the first user page,
// if this fails for any reason the transaction
// will roll back and the container will be dropped (removed)
ContainerHandle containerHdl = null;
Page firstPage = null;
try {
// make sure to open it with IS_KEPT too.
if (tmpContainer && ((temporaryFlag & TransactionController.IS_KEPT) == TransactionController.IS_KEPT)) {
mode |= ContainerHandle.MODE_TEMP_IS_KEPT;
}
// open no-locking as we already have the container locked
containerHdl = t.openContainer(identity, null, (ContainerHandle.MODE_FORUPDATE | mode));
// we just added it, containerHdl should not be null
if (SanityManager.DEBUG)
SanityManager.ASSERT(containerHdl != null);
if (!tmpContainer) {
// make it persistent (in concept if not in reality)
RawContainerHandle rch = (RawContainerHandle) containerHdl;
ContainerOperation lop = new ContainerOperation(rch, ContainerOperation.CREATE);
// mark the container as pre-dirtied so that if a checkpoint
// happens after the log record is sent to the log stream, the
// cache cleaning will wait for this change.
rch.preDirty(true);
try {
t.logAndDo(lop);
// flush the log to reduce the window between where
// the container is created & synced and the log record
// for it makes it to disk. If we fail in this
// window we will leave a stranded container file.
flush(t.getLastLogInstant());
} finally {
// in case logAndDo fail, make sure the container is not
// stuck in preDirty state.
rch.preDirty(false);
}
}
firstPage = containerHdl.addPage();
} finally {
if (firstPage != null) {
firstPage.unlatch();
firstPage = null;
}
containerCache.release(container);
if (containerHdl != null) {
containerHdl.close();
containerHdl = null;
}
if (!tmpContainer) {
// this should do nothing, since we requested isolation 3
// but we can't assume that, so call the policy correctly.
cl.unlockContainer(t, ch);
}
}
return containerId;
}
Aggregations