use of org.apache.ignite.internal.pagememory.io.PageIo in project ignite-3 by apache.
the class RandomLruPageReplacementPolicy method isStoreMetadataPage.
/**
* Return {@code true} if page is related to metadata.
*
* @param absPageAddr Absolute page address
*/
private boolean isStoreMetadataPage(long absPageAddr) {
try {
long dataAddr = absPageAddr + PAGE_OVERHEAD;
PageIo io = seg.ioRegistry().resolve(dataAddr);
return io instanceof PagesListMetaIo;
} catch (IgniteInternalCheckedException ignored) {
return false;
}
}
use of org.apache.ignite.internal.pagememory.io.PageIo in project ignite-3 by apache.
the class PageIoRegistryTest method testResolve.
@Test
void testResolve() throws Exception {
// Module is not yet loaded.
assertThrows(IgniteInternalCheckedException.class, () -> ioRegistry.resolve(TEST_PAGE_TYPE, TEST_PAGE_VER));
// Load all PageIOModule-s from the classpath.
ioRegistry.loadFromServiceLoader();
// Test base resolve method.
PageIo pageIo = ioRegistry.resolve(TEST_PAGE_TYPE, TEST_PAGE_VER);
assertTrue(pageIo instanceof TestPageIo);
assertEquals(TEST_PAGE_TYPE, pageIo.getType());
assertEquals(TEST_PAGE_VER, pageIo.getVersion());
ByteBuffer pageBuffer = ByteBuffer.allocateDirect(4);
pageBuffer.order(GridUnsafe.NATIVE_BYTE_ORDER);
pageBuffer.putShort(PageIo.TYPE_OFF, (short) TEST_PAGE_TYPE);
pageBuffer.putShort(PageIo.VER_OFF, (short) TEST_PAGE_VER);
// Test resolve from a pointer.
assertEquals(pageIo, ioRegistry.resolve(bufferAddress(pageBuffer)));
// Test resolve from ByteBuffer.
assertEquals(pageIo, ioRegistry.resolve(pageBuffer));
}
use of org.apache.ignite.internal.pagememory.io.PageIo in project ignite-3 by apache.
the class PagesList method takeEmptyPage.
/**
* Takes empty page from free list.
*
* @param bucket Bucket index.
* @param initIoVers Optional IO to initialize page.
* @param statHolder Statistics holder to track IO operations.
* @return Removed page ID.
* @throws IgniteInternalCheckedException If failed.
*/
protected long takeEmptyPage(int bucket, @Nullable IoVersions<?> initIoVers, IoStatisticsHolder statHolder) throws IgniteInternalCheckedException {
PagesCache pagesCache = getBucketCache(bucket, false);
long pageId;
if (pagesCache != null && (pageId = pagesCache.poll()) != 0L) {
decrementBucketSize(bucket);
if (log.isDebugEnabled()) {
log.debug("Take page from pages list cache [list=" + name() + ", bucket=" + bucket + ", pageId=" + pageId + ']');
}
assert !isReuseBucket(bucket) : "reuse bucket detected";
return pageId;
}
for (int lockAttempt = 0; ; ) {
Stripe stripe = getStripeForTake(bucket);
if (stripe == null) {
return 0L;
}
final long tailId = stripe.tailId;
// Stripe was removed from bucket concurrently.
if (tailId == 0L) {
continue;
}
final long tailPage = acquirePage(tailId, statHolder);
try {
// Explicit check.
long tailAddr = writeLockPage(tailId, tailPage, bucket, lockAttempt++, null);
if (tailAddr == 0L) {
continue;
}
if (stripe.empty || stripe.tailId != tailId) {
// Another thread took the last page.
writeUnlock(tailId, tailPage, tailAddr, false);
if (bucketsSize.get(bucket) > 0) {
// Ignore current attempt.
lockAttempt--;
continue;
} else {
return 0L;
}
}
assert getPageId(tailAddr) == tailId : "tailId = " + hexLong(tailId) + ", pageId = " + hexLong(getPageId(tailAddr));
assert getType(tailAddr) == T_PAGE_LIST_NODE : "tailId = " + hexLong(tailId) + ", type = " + getType(tailAddr);
boolean dirty = false;
long dataPageId;
long recycleId = 0L;
try {
PagesListNodeIo io = PagesListNodeIo.VERSIONS.forPage(tailAddr);
if (io.getNextId(tailAddr) != 0) {
// It is not a tail anymore, retry.
continue;
}
pageId = io.takeAnyPage(tailAddr);
if (pageId != 0L) {
decrementBucketSize(bucket);
dirty = true;
if (isReuseBucket(bucket) && !(itemId(pageId) > 0 && itemId(pageId) <= MAX_ITEMID_NUM)) {
throw corruptedFreeListException("Incorrectly recycled pageId in reuse bucket: " + hexLong(pageId), pageId);
}
if (isReuseBucket(bucket)) {
byte flag = getFlag(initIoVers);
PageIo initIo = initIoVers == null ? null : initIoVers.latest();
dataPageId = initRecycledPage0(pageId, flag, initIo);
} else {
dataPageId = pageId;
}
if (io.isEmpty(tailAddr)) {
long prevId = io.getPreviousId(tailAddr);
// to prevent empty page leak to data pages.
if (!isReuseBucket(bucket)) {
if (prevId != 0L) {
Boolean ok = write(prevId, cutTail, null, bucket, FALSE, statHolder);
assert ok == TRUE : ok;
recycleId = recyclePage(tailId, tailAddr);
} else {
stripe.empty = true;
}
} else {
stripe.empty = prevId == 0L;
}
}
} else {
// a previous page, so, the current page can be collected
assert isReuseBucket(bucket);
long prevId = io.getPreviousId(tailAddr);
assert prevId != 0L;
Boolean ok = write(prevId, cutTail, bucket, FALSE, statHolder);
assert ok == TRUE : ok;
decrementBucketSize(bucket);
byte flag = getFlag(initIoVers);
PageIo pageIo = initIoVers != null ? initIoVers.latest() : null;
dataPageId = initReusedPage(tailId, tailAddr, partitionId(tailId), flag, pageIo);
dirty = true;
}
// If we do not have a previous page (we are at head), then we still can return
// current page but we have to drop the whole stripe. Since it is a reuse bucket,
// we will not do that, but just return 0L, because this may produce contention on
// meta page.
} finally {
writeUnlock(tailId, tailPage, tailAddr, dirty);
}
// Put recycled page (if any) to the reuse bucket after tail is unlocked.
if (recycleId != 0L) {
assert !isReuseBucket(bucket);
reuseList.addForRecycle(new SingletonReuseBag(recycleId));
}
if (log.isDebugEnabled()) {
log.debug("Take page from pages list [list=" + name() + ", bucket=" + bucket + ", dataPageId=" + dataPageId + ", tailId=" + tailId + ']');
}
return dataPageId;
} finally {
releasePage(tailId, tailPage);
}
}
}
Aggregations