blob: c1234377fb010728967afb4b8d9ca096259e98dd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.pagememory.persistence;
import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX;
import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageId;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.UUID;
import org.apache.ignite.internal.pagememory.persistence.io.PartitionMetaIo;
import org.apache.ignite.internal.tostring.S;
import org.jetbrains.annotations.Nullable;
/**
* Partition meta information.
*/
public class PartitionMeta {
private static final VarHandle PAGE_COUNT;
private static final VarHandle META_SNAPSHOT;
static {
try {
PAGE_COUNT = MethodHandles.lookup().findVarHandle(PartitionMeta.class, "pageCount", int.class);
META_SNAPSHOT = MethodHandles.lookup().findVarHandle(PartitionMeta.class, "metaSnapshot", PartitionMetaSnapshot.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private volatile long lastAppliedIndex;
private volatile long versionChainTreeRootPageId;
private volatile long rowVersionFreeListRootPageId;
private volatile int pageCount;
private volatile PartitionMetaSnapshot metaSnapshot;
/**
* Default constructor.
*/
public PartitionMeta() {
metaSnapshot = new PartitionMetaSnapshot(null, this);
}
/**
* Constructor.
*
* @param checkpointId Checkpoint ID.
* @param lastAppliedIndex Last applied index value.
* @param versionChainTreeRootPageId Version chain tree root page ID.
* @param rowVersionFreeListRootPageId Row version free list root page ID.
* @param pageCount Count of pages in the partition.
*/
public PartitionMeta(
@Nullable UUID checkpointId,
long lastAppliedIndex,
long versionChainTreeRootPageId,
long rowVersionFreeListRootPageId,
int pageCount
) {
this.lastAppliedIndex = lastAppliedIndex;
this.versionChainTreeRootPageId = versionChainTreeRootPageId;
this.rowVersionFreeListRootPageId = rowVersionFreeListRootPageId;
this.pageCount = pageCount;
metaSnapshot = new PartitionMetaSnapshot(checkpointId, this);
}
/**
* Constructor.
*
* @param checkpointId Checkpoint ID.
* @param metaIo Partition meta IO.
* @param pageAddr Address of the page with the partition meta.
*/
PartitionMeta(@Nullable UUID checkpointId, PartitionMetaIo metaIo, long pageAddr) {
this(
checkpointId,
metaIo.getLastAppliedIndex(pageAddr),
metaIo.getVersionChainTreeRootPageId(pageAddr),
metaIo.getRowVersionFreeListRootPageId(pageAddr),
metaIo.getPageCount(pageAddr)
);
}
/**
* Returns a last applied index value.
*/
public long lastAppliedIndex() {
return lastAppliedIndex;
}
/**
* Sets a last applied index value.
*
* @param checkpointId Checkpoint ID.
* @param lastAppliedIndex Last applied index value.
*/
public void lastAppliedIndex(@Nullable UUID checkpointId, long lastAppliedIndex) {
updateSnapshot(checkpointId);
this.lastAppliedIndex = lastAppliedIndex;
}
/**
* Returns version chain tree root page ID.
*/
public long versionChainTreeRootPageId() {
return versionChainTreeRootPageId;
}
/**
* Sets version chain root page ID.
*
* @param checkpointId Checkpoint ID.
* @param versionChainTreeRootPageId Version chain root page ID.
*/
public void versionChainTreeRootPageId(@Nullable UUID checkpointId, long versionChainTreeRootPageId) {
updateSnapshot(checkpointId);
this.versionChainTreeRootPageId = versionChainTreeRootPageId;
}
/**
* Returns row version free list root page ID.
*/
public long rowVersionFreeListRootPageId() {
return rowVersionFreeListRootPageId;
}
/**
* Sets row version free list root page ID.
*
* @param checkpointId Checkpoint ID.
* @param rowVersionFreeListRootPageId Row version free list root page ID.
*/
public void rowVersionFreeListRootPageId(@Nullable UUID checkpointId, long rowVersionFreeListRootPageId) {
updateSnapshot(checkpointId);
this.rowVersionFreeListRootPageId = rowVersionFreeListRootPageId;
}
/**
* Returns count of pages in the partition.
*/
public int pageCount() {
return pageCount;
}
/**
* Increases the number of pages in a partition.
*/
public void incrementPageCount(@Nullable UUID checkpointId) {
updateSnapshot(checkpointId);
PAGE_COUNT.getAndAdd(this, 1);
}
/**
* Returns the latest snapshot of the partition meta.
*
* @param checkpointId Checkpoint ID.
*/
public PartitionMetaSnapshot metaSnapshot(@Nullable UUID checkpointId) {
updateSnapshot(checkpointId);
return metaSnapshot;
}
/**
* Takes a snapshot of the partition meta if the {@code checkpointId} is different from the {@link #metaSnapshot last snapshot} {@link
* PartitionMetaSnapshot#checkpointId}.
*
* @param checkpointId Checkpoint ID.
*/
private void updateSnapshot(@Nullable UUID checkpointId) {
PartitionMetaSnapshot current = metaSnapshot;
if (current.checkpointId != checkpointId) {
META_SNAPSHOT.compareAndSet(this, current, new PartitionMetaSnapshot(checkpointId, this));
}
}
/** {@inheritDoc} */
@Override
public String toString() {
return S.toString(PartitionMeta.class, this);
}
/**
* An immutable snapshot of the partition's meta information.
*/
public static class PartitionMetaSnapshot {
private final @Nullable UUID checkpointId;
private final long lastAppliedIndex;
private final long versionChainTreeRootPageId;
private final long rowVersionFreeListRootPageId;
private final int pageCount;
/**
* Private constructor.
*
* @param checkpointId Checkpoint ID.
* @param partitionMeta Partition meta.
*/
private PartitionMetaSnapshot(@Nullable UUID checkpointId, PartitionMeta partitionMeta) {
this.checkpointId = checkpointId;
this.lastAppliedIndex = partitionMeta.lastAppliedIndex;
this.versionChainTreeRootPageId = partitionMeta.versionChainTreeRootPageId;
this.rowVersionFreeListRootPageId = partitionMeta.rowVersionFreeListRootPageId;
this.pageCount = partitionMeta.pageCount;
}
/**
* Returns a last applied index value.
*/
public long lastAppliedIndex() {
return lastAppliedIndex;
}
/**
* Returns version chain tree root page ID.
*/
public long versionChainTreeRootPageId() {
return versionChainTreeRootPageId;
}
/**
* Returns row version free list root page ID.
*/
public long rowVersionFreeListRootPageId() {
return rowVersionFreeListRootPageId;
}
/**
* Returns count of pages in the partition.
*/
public int pageCount() {
return pageCount;
}
/**
* Writes the contents of the snapshot to a page of type {@link PartitionMetaIo}.
*
* @param metaIo Partition meta IO.
* @param pageAddr Address of the page with the partition meta.
*/
void writeTo(PartitionMetaIo metaIo, long pageAddr) {
metaIo.setLastAppliedIndex(pageAddr, lastAppliedIndex);
metaIo.setVersionChainTreeRootPageId(pageAddr, versionChainTreeRootPageId);
metaIo.setRowVersionFreeListRootPageId(pageAddr, rowVersionFreeListRootPageId);
metaIo.setPageCount(pageAddr, pageCount);
}
/** {@inheritDoc} */
@Override
public String toString() {
return S.toString(PartitionMetaSnapshot.class, this);
}
}
/**
* Gets partition metadata page ID for specified partId.
*
* @param partId Partition ID.
* @return Meta page for partId.
*/
public static long partitionMetaPageId(int partId) {
return pageId(partId, FLAG_AUX, 0);
}
}