Reduce GC pressure for checkpoints
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/fd8b711b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/fd8b711b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/fd8b711b Branch: refs/heads/ignite-5398 Commit: fd8b711b9edd6f76acb66b94dc3d12f3041fdfdd Parents: cde190d Author: Alexey Goncharuk <[email protected]> Authored: Wed May 24 18:27:43 2017 +0300 Committer: Alexey Goncharuk <[email protected]> Committed: Wed May 24 18:28:22 2017 +0300 ---------------------------------------------------------------------- .../internal/pagemem/wal/record/CacheState.java | 133 ++++++++++++------- .../cache/database/freelist/PagesList.java | 57 ++++++-- .../cache/database/tree/io/PageMetaIO.java | 7 +- .../database/tree/io/PagePartitionMetaIO.java | 28 +++- .../ignite/internal/util/IgniteUtils.java | 12 ++ 5 files changed, 173 insertions(+), 64 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/fd8b711b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/CacheState.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/CacheState.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/CacheState.java index 638acfa..1c8b04a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/CacheState.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/CacheState.java @@ -17,19 +17,28 @@ package org.apache.ignite.internal.pagemem.wal.record; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import org.apache.ignite.internal.util.tostring.GridToStringInclude; -import org.apache.ignite.internal.util.typedef.internal.S; +import java.util.Arrays; /** * */ public class CacheState { /** */ - @GridToStringInclude - private Map<Integer, PartitionState> parts; + private short[] parts; + + /** */ + private long[] vals; + + /** */ + private int idx; + + /** + * @param partsCnt Partitions count. + */ + public CacheState(int partsCnt) { + parts = new short[partsCnt]; + vals = new long[partsCnt * 2]; + } /** * @param partId Partition ID to add. @@ -37,60 +46,88 @@ public class CacheState { * @param cntr Partition counter. */ public void addPartitionState(int partId, long size, long cntr) { - if (parts == null) - parts = new HashMap<>(); + if (idx == parts.length) + throw new IllegalStateException("Failed to add new partition to the partitions state " + + "(no enough space reserved) [partId=" + partId + ", reserved=" + parts.length + ']'); + + if (idx > 0) { + if (parts[idx - 1] >= partId) + throw new IllegalStateException("Adding partition in a wrong order [prev=" + parts[idx - 1] + + ", cur=" + partId + ']'); + } + + parts[idx] = (short)partId; + vals[2 * idx] = size; + vals[2 * idx + 1] = cntr; - parts.put(partId, new PartitionState(size, cntr)); + idx++; } /** - * @return Partitions map. + * Gets partition size by partition ID. + * + * @param partId Partition ID. + * @return Partition size (will return {@code -1} if partition is not present in the record). */ - public Map<Integer, PartitionState> partitions() { - return parts == null ? Collections.<Integer, PartitionState>emptyMap() : parts; - } + public long sizeByPartition(int partId) { + int idx = indexByPartition(partId); - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(CacheState.class, this); + return idx >= 0 ? vals[2 * idx] : -1; } /** + * Gets partition counter by partition ID. * + * @param partId Partition ID. + * @return Partition update counter (will return {@code -1} if partition is not present in the record). */ - public static class PartitionState { - /** */ - private final long size; - - /** */ - private final long partCnt; - - /** - * @param size Partition size. - * @param partCnt Partition counter. - */ - public PartitionState(long size, long partCnt) { - this.size = size; - this.partCnt = partCnt; - } + public long counterByPartition(int partId) { + int idx = indexByPartition(partId); - /** - * @return Partition size. - */ - public long size() { - return size; - } + return idx >= 0 ? vals[2 * idx + 1] : 0; + } - /** - * @return Partition counter. - */ - public long partitionCounter() { - return partCnt; - } + /** + * @param idx Index to get. + * @return Partition ID. + */ + public int partitionByIndex(int idx) { + return parts[idx] & 0xFFFF; + } - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(PartitionState.class, this); - } + /** + * @param idx Index to get. + * @return Partition size by index. + */ + public long partitionSizeByIndex(int idx) { + return vals[idx * 2]; + } + + /** + * @param idx Index to get. + * @return Partition size by index. + */ + public long partitionCounterByIndex(int idx) { + return vals[idx * 2 + 1]; + } + + /** + * @return State size. + */ + public int size() { + return idx; + } + + /** + * @param partId Partition ID to search. + * @return Non-negative index of partition if found or negative value if not found. + */ + private int indexByPartition(int partId) { + return Arrays.binarySearch(parts, 0, idx, (short)partId); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "CacheState [cap=" + parts.length + ", size=" + idx + ']'; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/fd8b711b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/PagesList.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/PagesList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/PagesList.java index 5c66b10..894f6e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/PagesList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/freelist/PagesList.java @@ -78,6 +78,9 @@ public abstract class PagesList extends DataStructure { /** */ protected final AtomicLong[] bucketsSize; + /** */ + protected volatile boolean changed; + /** Page ID to store list metadata. */ private final long metaPageId; @@ -123,16 +126,15 @@ public abstract class PagesList extends DataStructure { * @param buckets Number of buckets. * @param wal Write ahead log manager. * @param metaPageId Metadata page ID. - * @throws IgniteCheckedException If failed. */ - public PagesList( + protected PagesList( int cacheId, String name, PageMemory pageMem, int buckets, IgniteWriteAheadLogManager wal, long metaPageId - ) throws IgniteCheckedException { + ) { super(cacheId, pageMem, wal); this.name = name; @@ -234,6 +236,8 @@ public abstract class PagesList extends DataStructure { assert ok; bucketsSize[bucket].set(bucketSize); + + changed = true; } } } @@ -251,6 +255,9 @@ public abstract class PagesList extends DataStructure { long nextPageId = metaPageId; + if (!changed) + return; + try { for (int bucket = 0; bucket < buckets; bucket++) { Stripe[] tails = getBucket(bucket); @@ -322,6 +329,8 @@ public abstract class PagesList extends DataStructure { } } } + + changed = false; } /** @@ -637,7 +646,7 @@ public abstract class PagesList extends DataStructure { if (idx == -1) handlePageFull(pageId, page, pageAddr, io, dataPage, dataPageAddr, bucket); else { - bucketsSize[bucket].incrementAndGet(); + incrementBucketSize(bucket); if (isWalDeltaRecordNeeded(wal, page)) wal.log(new PagesListAddPageRecord(cacheId, pageId, dataPageId)); @@ -697,7 +706,7 @@ public abstract class PagesList extends DataStructure { pageId, 0L)); // In reuse bucket the page itself can be used as a free page. - bucketsSize[bucket].incrementAndGet(); + incrementBucketSize(bucket); updateTail(bucket, pageId, dataPageId); } @@ -739,7 +748,7 @@ public abstract class PagesList extends DataStructure { if (isWalDeltaRecordNeeded(wal, dataPage)) wal.log(new DataPageSetFreeListPageRecord(cacheId, dataPageId, nextId)); - bucketsSize[bucket].incrementAndGet(); + incrementBucketSize(bucket); updateTail(bucket, pageId, nextId); } @@ -818,7 +827,7 @@ public abstract class PagesList extends DataStructure { // In reuse bucket the page itself can be used as a free page. if (isReuseBucket(bucket)) - bucketsSize[bucket].incrementAndGet(); + incrementBucketSize(bucket); // Switch to this new page, which is now a part of our list // to add the rest of the bag to the new page. @@ -832,7 +841,7 @@ public abstract class PagesList extends DataStructure { if (isWalDeltaRecordNeeded(wal, page)) wal.log(new PagesListAddPageRecord(cacheId, prevId, nextId)); - bucketsSize[bucket].incrementAndGet(); + incrementBucketSize(bucket); } } } @@ -972,7 +981,7 @@ public abstract class PagesList extends DataStructure { long pageId = io.takeAnyPage(tailPageAddr); if (pageId != 0L) { - bucketsSize[bucket].decrementAndGet(); + decrementBucketSize(bucket); if (isWalDeltaRecordNeeded(wal, tail)) wal.log(new PagesListRemovePageRecord(cacheId, tailId, pageId)); @@ -1020,7 +1029,7 @@ public abstract class PagesList extends DataStructure { assert ok == TRUE : ok; - bucketsSize[bucket].decrementAndGet(); + decrementBucketSize(bucket); } if (initIoVers != null) { @@ -1100,7 +1109,7 @@ public abstract class PagesList extends DataStructure { if (!rmvd) return false; - bucketsSize[bucket].decrementAndGet(); + decrementBucketSize(bucket); if (isWalDeltaRecordNeeded(wal, page)) wal.log(new PagesListRemovePageRecord(cacheId, pageId, dataPageId)); @@ -1340,6 +1349,32 @@ public abstract class PagesList extends DataStructure { } /** + * Increments bucket size and updates changed flag. + * + * @param bucket Bucket number. + */ + private void incrementBucketSize(int bucket) { + bucketsSize[bucket].incrementAndGet(); + + // Ok to have a race here, see the field javadoc. + if (!changed) + changed = true; + } + + /** + * Increments bucket size and updates changed flag. + * + * @param bucket Bucket number. + */ + private void decrementBucketSize(int bucket) { + bucketsSize[bucket].decrementAndGet(); + + // Ok to have a race here, see the field javadoc. + if (!changed) + changed = true; + } + + /** * Singleton reuse bag. */ private static final class SingletonReuseBag implements ReuseBag { http://git-wip-us.apache.org/repos/asf/ignite/blob/fd8b711b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageMetaIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageMetaIO.java index 7a5535c..b04baf3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageMetaIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageMetaIO.java @@ -204,8 +204,13 @@ public class PageMetaIO extends PageIO { * @param pageAddr Page address. * @param pageCnt Last page count. */ - public void setCandidatePageCount(long pageAddr, int pageCnt) { + public boolean setCandidatePageCount(long pageAddr, int pageCnt) { + if (getCandidatePageCount(pageAddr) == pageCnt) + return false; + PageUtils.putInt(pageAddr, CANDIDATE_PAGE_COUNT_OFF, pageCnt); + + return true; } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/fd8b711b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PagePartitionMetaIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PagePartitionMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PagePartitionMetaIO.java index aca0725..5276815 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PagePartitionMetaIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PagePartitionMetaIO.java @@ -70,8 +70,13 @@ public class PagePartitionMetaIO extends PageMetaIO { * @param pageAddr Page address. * @param size Partition size. */ - public void setSize(long pageAddr, long size) { + public boolean setSize(long pageAddr, long size) { + if (getSize(pageAddr) == size) + return false; + PageUtils.putLong(pageAddr, SIZE_OFF, size); + + return true; } /** @@ -86,8 +91,13 @@ public class PagePartitionMetaIO extends PageMetaIO { * @param pageAddr Page address. * @param cntr Partition update counter. */ - public void setUpdateCounter(long pageAddr, long cntr) { + public boolean setUpdateCounter(long pageAddr, long cntr) { + if (getUpdateCounter(pageAddr) == cntr) + return false; + PageUtils.putLong(pageAddr, UPDATE_CNTR_OFF, cntr); + + return true; } /** @@ -102,8 +112,13 @@ public class PagePartitionMetaIO extends PageMetaIO { * @param pageAddr Page address. * @param rmvId Global remove ID. */ - public void setGlobalRemoveId(long pageAddr, long rmvId) { + public boolean setGlobalRemoveId(long pageAddr, long rmvId) { + if (getGlobalRemoveId(pageAddr) == rmvId) + return false; + PageUtils.putLong(pageAddr, GLOBAL_RMV_ID_OFF, rmvId); + + return true; } /** @@ -117,7 +132,12 @@ public class PagePartitionMetaIO extends PageMetaIO { * @param pageAddr Page address * @param state State. */ - public void setPartitionState(long pageAddr, byte state) { + public boolean setPartitionState(long pageAddr, byte state) { + if (getPartitionState(pageAddr) == state) + return false; + PageUtils.putByte(pageAddr, PARTITION_STATE_OFF, state); + + return true; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/fd8b711b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index e8cb32b..fa6c6d6 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -8585,6 +8585,18 @@ public abstract class IgniteUtils { } /** + * A primitive override of {@link #hash(Object)} to avoid unnecessary boxing. + * + * @param key Value to hash. + * @return Hash value. + */ + public static int hash(long key) { + int val = (int)(key ^ (key >>> 32)); + + return hash(val); + } + + /** * @return PID of the current JVM or {@code -1} if it can't be determined. */ public static int jvmPid() {
