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() {

Reply via email to