From f2f128187b35997923cd50e8a97a4f2931bfdaf0 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 27 May 2019 13:48:32 +0300 Subject: [PATCH 01/50] IGNITE-11584 Batch write into page memory. --- .../processors/cache/GridCacheEntryEx.java | 39 +- .../processors/cache/GridCacheMapEntry.java | 29 +- .../cache/IgniteCacheOffheapManager.java | 25 ++ .../cache/IgniteCacheOffheapManagerImpl.java | 57 +++ .../preloader/GridDhtPartitionDemander.java | 167 ++++++++- .../persistence/GridCacheOffheapManager.java | 14 + .../cache/persistence/RowStore.java | 11 + .../freelist/AbstractFreeList.java | 271 +++++++++++--- .../cache/persistence/freelist/FreeList.java | 7 + .../persistence/tree/util/PageHandler.java | 37 +- .../cache/GridCacheTestEntryEx.java | 3 +- .../rebalancing/PreloadingFlowTest.java | 351 ++++++++++++++++++ .../MemoryLeakAfterRebalanceSelfTest.java | 217 +++++++++++ .../database/CacheFreeListSelfTest.java | 86 ++++- .../testsuites/IgnitePdsMvccTestSuite.java | 3 + .../ignite/testsuites/IgnitePdsTestSuite.java | 3 + 16 files changed, 1245 insertions(+), 75 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java index 9aec3996c32046..71702edf87ca22 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java @@ -792,6 +792,42 @@ default boolean initialValue(CacheObject val, * @throws IgniteCheckedException In case of error. * @throws GridCacheEntryRemovedException If entry was removed. */ + default boolean initialValue(CacheObject val, + GridCacheVersion ver, + @Nullable MvccVersion mvccVer, + @Nullable MvccVersion newMvccVer, + byte mvccTxState, + byte newMvccTxState, + long ttl, + long expireTime, + boolean preload, + AffinityTopologyVersion topVer, + GridDrType drType, + boolean fromStore) throws IgniteCheckedException, GridCacheEntryRemovedException { + return initialValue(val, ver, null, null, TxState.NA, TxState.NA, + ttl, expireTime, preload, topVer, drType, fromStore, null); + } + + /** + * Sets new value if current version is 0 + * + * @param val New value. + * @param ver Version to use. + * @param mvccVer Mvcc version. + * @param newMvccVer New mvcc version. + * @param mvccTxState Tx state hint for mvcc version. + * @param newMvccTxState Tx state hint for new mvcc version. + * @param ttl Time to live. + * @param expireTime Expiration time. + * @param preload Flag indicating whether entry is being preloaded. + * @param topVer Topology version. + * @param drType DR type. + * @param fromStore {@code True} if value was loaded from store. + * @param row Pre-created data row, associated with this cache entry. + * @return {@code True} if initial value was set. + * @throws IgniteCheckedException In case of error. + * @throws GridCacheEntryRemovedException If entry was removed. + */ public boolean initialValue(CacheObject val, GridCacheVersion ver, @Nullable MvccVersion mvccVer, @@ -803,7 +839,8 @@ public boolean initialValue(CacheObject val, boolean preload, AffinityTopologyVersion topVer, GridDrType drType, - boolean fromStore) throws IgniteCheckedException, GridCacheEntryRemovedException; + boolean fromStore, + @Nullable CacheDataRow row) throws IgniteCheckedException, GridCacheEntryRemovedException; /** * Create versioned entry for this cache entry. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java index f1b7ec76b2152f..02cc42b0dfe050 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java @@ -3310,7 +3310,8 @@ private boolean skipInterceptor(@Nullable GridCacheVersion explicitVer) { boolean preload, AffinityTopologyVersion topVer, GridDrType drType, - boolean fromStore + boolean fromStore, + CacheDataRow row ) throws IgniteCheckedException, GridCacheEntryRemovedException { ensureFreeSpace(); @@ -3386,7 +3387,7 @@ else if (val == null) cctx.offheap().mvccInitialValue(this, val, ver, expTime, mvccVer, newMvccVer); } else - storeValue(val, expTime, ver); + storeValue(val, expTime, ver, null, row); } } else { @@ -3417,7 +3418,7 @@ else if (val == null) } else // Optimization to access storage only once. - update = storeValue(val, expTime, ver, p); + update = storeValue(val, expTime, ver, p, row); } if (update) { @@ -4257,7 +4258,7 @@ private IgniteTxLocalAdapter currentTx() { protected boolean storeValue(@Nullable CacheObject val, long expireTime, GridCacheVersion ver) throws IgniteCheckedException { - return storeValue(val, expireTime, ver, null); + return storeValue(val, expireTime, ver, null, null); } /** @@ -4267,6 +4268,7 @@ protected boolean storeValue(@Nullable CacheObject val, * @param expireTime Expire time. * @param ver New entry version. * @param predicate Optional predicate. + * @param row Pre-created data row, associated with this cache entry. * @return {@code True} if storage was modified. * @throws IgniteCheckedException If update failed. */ @@ -4274,10 +4276,12 @@ protected boolean storeValue( @Nullable CacheObject val, long expireTime, GridCacheVersion ver, - @Nullable IgnitePredicate predicate) throws IgniteCheckedException { + @Nullable IgnitePredicate predicate, + @Nullable CacheDataRow row + ) throws IgniteCheckedException { assert lock.isHeldByCurrentThread(); - UpdateClosure closure = new UpdateClosure(this, val, ver, expireTime, predicate); + UpdateClosure closure = new UpdateClosure(this, val, ver, expireTime, predicate, row); cctx.offheap().invoke(cctx, key, localPartition(), closure); @@ -5716,16 +5720,19 @@ private static class UpdateClosure implements IgniteCacheOffheapManager.OffheapI * @param predicate Optional predicate. */ UpdateClosure(GridCacheMapEntry entry, @Nullable CacheObject val, GridCacheVersion ver, long expireTime, - @Nullable IgnitePredicate predicate) { + @Nullable IgnitePredicate predicate, @Nullable CacheDataRow newRow) { this.entry = entry; this.val = val; this.ver = ver; this.expireTime = expireTime; this.predicate = predicate; + this.newRow = newRow; } /** {@inheritDoc} */ @Override public void call(@Nullable CacheDataRow oldRow) throws IgniteCheckedException { + assert newRow == null || val != null; + if (oldRow != null) { oldRow.key(entry.key); @@ -5741,6 +5748,14 @@ private static class UpdateClosure implements IgniteCacheOffheapManager.OffheapI } if (val != null) { + // If there is a pre created row, we cannot update the old one. + // The old row will be removed after the operation is completed, as usual. + if (newRow != null) { + treeOp = IgniteTree.OperationType.PUT; + + return; + } + newRow = entry.cctx.offheap().dataStore(entry.localPartition()).createRow( entry.cctx, entry.key, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index ab8d338e46b051..507bbc96c46cd4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache; +import java.util.Collection; import java.util.List; import java.util.Map; import javax.cache.Cache; @@ -190,6 +191,18 @@ public boolean expire(GridCacheContext cctx, IgniteInClosure2X storeAll( + GridCacheContext cctx, + GridDhtLocalPartition part, + Collection entries + ) throws IgniteCheckedException; + /** * @param cctx Cache context. * @param key Key. @@ -729,6 +742,18 @@ void update( long expireTime, @Nullable CacheDataRow oldRow) throws IgniteCheckedException; + + /** + * @param cctx Cache context. + * @param entries Entries. + * @return Created rows. + * @throws IgniteCheckedException If failed. + */ + public List storeAll( + GridCacheContext cctx, + Collection entries + ) throws IgniteCheckedException; + /** * @param cctx Cache context. * @param key Key. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index ff87d7059a03f8..b15e71ce8fd49f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.processors.cache; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -446,6 +447,15 @@ private Iterator cacheData(boolean primary, boolean backup, Affi dataStore(part).invoke(cctx, key, c); } + /** {@inheritDoc} */ + @Override public List storeAll( + GridCacheContext cctx, + GridDhtLocalPartition part, + Collection entries + ) throws IgniteCheckedException { + return dataStore(part).storeAll(cctx, entries); + } + /** {@inheritDoc} */ @Override public void update( GridCacheContext cctx, @@ -1693,6 +1703,53 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } } + /** {@inheritDoc} */ + @Override public List storeAll( + GridCacheContext cctx, + Collection infos + ) throws IgniteCheckedException { + if (!busyLock.enterBusy()) + throw new NodeStoppingException("Operation has been cancelled (node is stopping)."); + + List rows = new ArrayList<>(infos.size()); + + try { + assert cctx.shared().database().checkpointLockIsHeldByThread(); + + assert !cctx.mvccEnabled(); + + int cacheId = cctx.group().storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; + + IoStatisticsHolder statHolder = grp.statisticsHolderData(); + + for (GridCacheEntryInfo info : infos) { + KeyCacheObject key = info.key(); + CacheObject val = info.value(); + + CacheObjectContext coCtx = cctx.cacheObjectContext(); + + key.valueBytes(coCtx); + val.valueBytes(coCtx); + + DataRow row = makeDataRow(key, val, info.version(), info.expireTime(), cacheId); + + rows.add(row); + } + + rowStore().addRows(rows, statHolder); + + if (grp.sharedGroup() && !cctx.group().storeCacheIdInDataPage()) { + for (CacheDataRow row : rows) + ((DataRow)row).cacheId(cctx.cacheId()); + } + } + finally { + busyLock.leaveBusy(); + } + + return rows; + } + /** {@inheritDoc} */ @Override public CacheDataRow createRow( GridCacheContext cctx, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 1c17a6fcd9e566..7f7b1613004100 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -34,12 +34,15 @@ import org.apache.ignite.cache.CacheRebalanceMode; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataPageEvictionMode; +import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.DiscoveryEvent; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.affinity.AffinityAssignment; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection; @@ -58,6 +61,9 @@ import org.apache.ignite.internal.processors.cache.mvcc.MvccUpdateVersionAware; import org.apache.ignite.internal.processors.cache.mvcc.MvccVersionAware; import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxState; +import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; +import org.apache.ignite.internal.processors.cache.persistence.DataRegion; +import org.apache.ignite.internal.processors.cache.persistence.RowStore; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; import org.apache.ignite.internal.util.future.GridCompoundFuture; @@ -67,6 +73,7 @@ import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.CI1; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.S; @@ -88,6 +95,9 @@ * Thread pool for requesting partitions from other nodes and populating local cache. */ public class GridDhtPartitionDemander { + /** */ + private static final int CHECKPOINT_THRESHOLD = 100; + /** */ private final GridCacheSharedContext ctx; @@ -765,6 +775,8 @@ public void handleSupplyMessage( boolean last = supplyMsg.last().containsKey(p); + boolean batched = evictionAllowsBatch(grp.dataRegion(), supplyMsg.messageSize()); + if (part.state() == MOVING) { boolean reserved = part.reserve(); @@ -779,7 +791,7 @@ public void handleSupplyMessage( if (grp.mvccEnabled()) mvccPreloadEntries(topVer, node, p, infos); else - preloadEntries(topVer, node, p, infos); + preloadEntries(topVer, node, p, infos, batched); // If message was last for this partition, // then we take ownership. @@ -859,6 +871,127 @@ public void handleSupplyMessage( } } + /** + * @param region Memory region. + * @param msgSize Rebalance message size. + * @return {@code True} if entries could processed in batch. + */ + private boolean evictionAllowsBatch(DataRegion region, int msgSize) { + DataRegionConfiguration plc = region.config(); + + if (plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) + return true; + + PageMemory pageMem = region.pageMemory(); + + int sysPageSize = pageMem.systemPageSize(); + + int pagesRequired = (msgSize / sysPageSize) * 2; + + long maxPages = plc.getMaxSize() / sysPageSize; + + // There are enough pages left. + if (pagesRequired < maxPages - pageMem.loadedPages()) + return true; + + // Empty pages pool size restricted. + if (pagesRequired > plc.getEmptyPagesPoolSize()) + return false; + + return pagesRequired < maxPages * (1.0d - plc.getEvictionThreshold()); + } + + /** + * @param from Node which sent entry. + * @param p Partition id. + * @param infos Preloaded entries. + * @param topVer Topology version. + * @param batchSize Batch size. + * @throws IgniteCheckedException If failed. + */ + private boolean preloadEntriesBatched( + AffinityTopologyVersion topVer, + ClusterNode from, + int p, + Iterator infos, + int batchSize + ) throws IgniteCheckedException { + Map> cctxs = new HashMap<>(); + + // Groupping by cache id, since we cannot place entries from different caches on the same page. + for (GridCacheEntryInfo e; infos.hasNext() && batchSize-- > 0; + e = infos.next(), cctxs.computeIfAbsent(e.cacheId(), v -> new ArrayList<>(8)).add(e)); + + for (Map.Entry> cctxEntry : cctxs.entrySet()) { + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(cctxEntry.getKey()) : grp.singleCacheContext(); + + if (cctx == null) + continue; + + if (cctx.isNear()) + cctx = cctx.dhtCache().context(); + + List cctxInfos = cctxEntry.getValue(); + + Iterator rowsItr = null; + + try { + GridDhtLocalPartition part = cctx.topology().localPartition(p); + + // Filter NULL values (it means that we should remove entry from cache). + Collection hasValues = F.view(cctxInfos, info -> info.value() != null); + + cctx.shared().database().ensureFreeSpace(cctx.dataRegion()); + + // Store all cache entries to data store before get locks. + rowsItr = cctx.offheap().storeAll(cctx, part, hasValues).iterator(); + + for (GridCacheEntryInfo info : cctxInfos) { + CacheDataRow row = info.value() == null ? null : rowsItr.next(); + + // Link created cache entry in BPlusTree. + if (!preloadEntry(from, p, info, topVer, cctx, row)) + return false; + + //TODO: IGNITE-11330: Update metrics for touched cache only. + for (GridCacheContext cctx0 : grp.caches()) { + if (cctx0.statisticsEnabled()) + cctx0.cache().metrics0().onRebalanceKeyReceived(); + } + } + } + catch (GridDhtInvalidPartitionException ignored) { + if (log.isDebugEnabled()) + log.debug("Partition became invalid during rebalancing (will ignore): " + p); + + return false; + } + finally { + // Remove all unprocessed rows on error. + while (rowsItr != null && rowsItr.hasNext()) + cleanupRow(cctx, rowsItr.next()); + } + } + + return true; + } + + /** + * Remove row from data store. + * + * @param cctx Cache context. + * @param row Row to remove. + * @throws IgniteCheckedException If failed. + */ + private void cleanupRow(GridCacheContext cctx, CacheDataRow row) throws IgniteCheckedException { + if (row != null) { + RowStore rowStore = cctx.offheap().dataStore(cctx.topology().localPartition(row.partition())).rowStore(); + + rowStore.removeRow(row.link(), grp.statisticsHolderData()); + } + } + /** * Adds mvcc entries with theirs history to partition p. * @@ -952,10 +1085,11 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node * @param p Partition id. * @param infos Entries info for preload. * @param topVer Topology version. + * @param batched Preload entries in batch mode. * @throws IgniteInterruptedCheckedException If interrupted. */ private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p, - Iterator infos) throws IgniteCheckedException { + Iterator infos, boolean batched) throws IgniteCheckedException { GridCacheContext cctx = null; // Loop through all received entries and try to preload them. @@ -963,7 +1097,19 @@ private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, in ctx.database().checkpointReadLock(); try { - for (int i = 0; i < 100; i++) { + if (batched) { + if (!preloadEntriesBatched(topVer, node, p, infos, CHECKPOINT_THRESHOLD)) { + if (log.isTraceEnabled()) + log.trace("Got entries for invalid partition during " + + "preloading (will skip) [p=" + p + ']'); + + return; + } + + continue; + } + + for (int i = 0; i < CHECKPOINT_THRESHOLD; i++) { if (!infos.hasNext()) break; @@ -978,7 +1124,7 @@ else if (cctx.isNear()) cctx = cctx.dhtCache().context(); } - if (!preloadEntry(node, p, entry, topVer, cctx)) { + if (!preloadEntry(node, p, entry, topVer, cctx, null)) { if (log.isTraceEnabled()) log.trace("Got entries for invalid partition during " + "preloading (will skip) [p=" + p + ", entry=" + entry + ']'); @@ -1007,6 +1153,7 @@ else if (cctx.isNear()) * @param entry Preloaded entry. * @param topVer Topology version. * @param cctx Cache context. + * @param row Pre-created data row, associated with this cache entry. * @return {@code False} if partition has become invalid during preloading. * @throws IgniteInterruptedCheckedException If interrupted. */ @@ -1015,7 +1162,8 @@ private boolean preloadEntry( int p, GridCacheEntryInfo entry, AffinityTopologyVersion topVer, - GridCacheContext cctx + GridCacheContext cctx, + CacheDataRow row ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); @@ -1043,7 +1191,8 @@ private boolean preloadEntry( true, topVer, cctx.isDrEnabled() ? DR_PRELOAD : DR_NONE, - false + false, + row )) { cached.touch(); // Start tracking. @@ -1055,18 +1204,20 @@ private boolean preloadEntry( else { cached.touch(); // Start tracking. + cleanupRow(cctx, row); // Remove pre-created row. + if (log.isTraceEnabled()) log.trace("Rebalancing entry is already in cache (will ignore) [key=" + cached.key() + ", part=" + p + ']'); } } - else if (log.isTraceEnabled()) - log.trace("Rebalance predicate evaluated to false for entry (will ignore): " + entry); } catch (GridCacheEntryRemovedException ignored) { if (log.isTraceEnabled()) log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" + cached.key() + ", part=" + p + ']'); + + cleanupRow(cctx, row); } catch (GridDhtInvalidPartitionException ignored) { if (log.isDebugEnabled()) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index c5045baa24bbad..75ea0ed8d726e1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.processors.cache.persistence; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -59,6 +60,7 @@ import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; +import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheTtlManager; import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManagerImpl; @@ -2399,6 +2401,18 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { delegate.invoke(cctx, key, c); } + /** {@inheritDoc} */ + @Override public List storeAll( + GridCacheContext cctx, + Collection entries + ) throws IgniteCheckedException { + assert ctx.database().checkpointLockIsHeldByThread(); + + CacheDataStore delegate = init0(false); + + return delegate.storeAll(cctx, entries); + } + /** {@inheritDoc} */ @Override public void remove(GridCacheContext cctx, KeyCacheObject key, int partId) throws IgniteCheckedException { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java index 9a3d9d28756deb..93d962489728e3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence; +import java.util.Collection; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; @@ -117,6 +118,16 @@ public void addRow(CacheDataRow row, IoStatisticsHolder statHolder) throws Ignit ", link=" + U.hexLong(row.link()) + ']'; } + /** + * @param rows Rows. + * @throws IgniteCheckedException If failed. + */ + public void addRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { + assert ctx.database().checkpointLockIsHeldByThread(); + + freeList.insertDataRows(rows.iterator(), statHolder); + } + /** * @param link Row link. * @param row New row data. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 22a79cc7a2061d..7b1aa5a47150a3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence.freelist; +import java.util.Iterator; import java.util.concurrent.atomic.AtomicReferenceArray; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; @@ -159,15 +160,6 @@ private final class WriteRowHandler extends PageHandler { written = (written == 0 && oldFreeSpace >= rowSize) ? addRow(pageId, page, pageAddr, io, row, rowSize) : addRowFragment(pageId, page, pageAddr, io, row, written, rowSize); - // Reread free space after update. - int newFreeSpace = io.getFreeSpace(pageAddr); - - if (newFreeSpace > MIN_PAGE_FREE_SPACE) { - int bucket = bucket(newFreeSpace, false); - - put(null, pageId, page, pageAddr, bucket, statHolder); - } - if (written == rowSize) evictionTracker.touchPage(pageId); @@ -473,71 +465,262 @@ private long allocateDataPage(int part) throws IgniteCheckedException { /** {@inheritDoc} */ @Override public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - int rowSize = row.size(); + try { + int written = writeLargeFragments(row, statHolder); - int written = 0; + if (written == COMPLETE) + return; - try { - do { - if (written != 0) - memMetrics.incrementLargeEntriesPages(); + int remaining = row.size() - written; - int remaining = rowSize - written; + long pageId = takePage(bucket(remaining, false) + 1, REUSE_BUCKET, row, statHolder); - long pageId = 0L; + AbstractDataPageIO initIo = null; - if (remaining < MIN_SIZE_FOR_DATA_PAGE) { - for (int b = bucket(remaining, false) + 1; b < BUCKETS - 1; b++) { - pageId = takeEmptyPage(b, row.ioVersions(), statHolder); + if (pageId == 0L) { + pageId = allocateDataPage(row.partition()); - if (pageId != 0L) - break; - } + initIo = row.ioVersions().latest(); + } + + long page = pageMem.acquirePage(grpId, pageId, statHolder); + + boolean releaseAfterWrite = true; + + try { + long pageAddr = writeLock(pageId, page); + + assert pageAddr != 0; + + AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); + + boolean ok = false; + + try { + PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, initIo, wal, + null, row, written, statHolder); + + ok = true; } + finally { + putPage(io.getFreeSpace(pageAddr), pageId, page, pageAddr, statHolder); - if (pageId == 0L) { // Handle reuse bucket. - if (reuseList == this) - pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); - else - pageId = reuseList.takeRecycledPage(); + if (releaseAfterWrite = writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0)) + writeUnlock(pageId, page, pageAddr, ok); + } + } + finally { + if (releaseAfterWrite) + pageMem.releasePage(grpId, pageId, page); + } + } + catch (IgniteCheckedException | Error e) { + throw e; + } + catch (Throwable t) { + throw new CorruptedFreeListException("Failed to insert data row", t); + } + } + + /** {@inheritDoc} */ + @Override public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException { + assert iter.hasNext(); + + try { + T row = iter.next(); + + int written = 0; + + while (written != COMPLETE || row.link() == 0) { + if ((written = writeLargeFragments(row, statHolder)) == COMPLETE) { + row = iter.hasNext() ? iter.next() : row; + + continue; } AbstractDataPageIO initIo = null; - if (pageId == 0L) { + int rowSize = row.size(); + + int minBucket = bucket(rowSize % MIN_SIZE_FOR_DATA_PAGE, false); + + long pageId = takePage(REUSE_BUCKET - 1, minBucket, row, statHolder); + + if (pageId == 0) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. - pageId = initReusedPage(row, pageId, row.partition(), statHolder); - else // Page is taken from free space bucket. For in-memory mode partition must be changed. - pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); + long page = pageMem.acquirePage(grpId, pageId, statHolder); + + boolean releaseAfterWrite = true; + + try { + long pageAddr = writeLock(pageId, page); + + assert pageAddr != 0; + + AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); + + boolean ok = false; + + try { + do { + boolean largeRow = rowSize > MIN_SIZE_FOR_DATA_PAGE; + + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, + initIo, wal, null, row, largeRow ? written : 0, statHolder); + + assert written == COMPLETE : written; + + initIo = null; + + while (iter.hasNext() && written == COMPLETE) { + row = iter.next(); + + written = writeLargeFragments(row, statHolder); + } + + rowSize = row.size(); + } + while (iter.hasNext() && io.getFreeSpace(pageAddr) >= (rowSize % MIN_SIZE_FOR_DATA_PAGE)); + + ok = true; + } + finally { + putPage(io.getFreeSpace(pageAddr), pageId, page, pageAddr, statHolder); - assert written != FAIL_I; // We can't fail here. + if (releaseAfterWrite = writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0)) + writeUnlock(pageId, page, pageAddr, ok); + } + } + finally { + if (releaseAfterWrite) + pageMem.releasePage(grpId, pageId, page); + } } - while (written != COMPLETE); } - catch (IgniteCheckedException | Error e) { - throw e; + catch (RuntimeException e) { + throw new CorruptedFreeListException("Failed to insert data rows", e); } - catch (Throwable t) { - throw new CorruptedFreeListException("Failed to insert data row", t); + } + + /** + * Take page from freelist. + * + * @param from Start bucket. + * @param to Finish bucket. + * @param row Row to process. + * @param statHolder Statistics holder to track IO operations. + * @return Page ID or {@code 0} if none available. + * @throws IgniteCheckedException If failed. + */ + private long takePage(int from, int to, T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + long pageId = 0; + + int partId = row.partition(); + + int direction = from < to ? 1 : -1; + + for (int b = from; b != to; b += direction) { + pageId = takeEmptyPage(b, row.ioVersions(), statHolder); + + if (pageId != 0L) + break; } + + if (pageId == 0) { + if (reuseList == this) + pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); + else + pageId = reuseList.takeRecycledPage(); + } + + if (pageId == 0) + return 0; + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + return initReusedPage(row, pageId, statHolder); + else // Page is taken from free space bucket. For in-memory mode partition must be changed. + return PageIdUtils.changePartitionId(pageId, partId); + } + + /** + * Put page into freelist. + * + * @param freespace Page free space. + * @param pageId Page ID. + * @param page Page pointer. + * @param pageAddr Page address. + * @param statHolder Statistics holder to track IO operations. + * @throws IgniteCheckedException If failed. + */ + private void putPage( + int freespace, + long pageId, + long page, + long pageAddr, + IoStatisticsHolder statHolder + ) throws IgniteCheckedException { + if (freespace > MIN_PAGE_FREE_SPACE) { + int bucket = bucket(freespace, false); + + put(null, pageId, page, pageAddr, bucket, statHolder); + } + + assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 + } + + /** + * Write fragments of the row, which occupy the whole memory page. + * + * @param row Row to process. + * @param statHolder Statistics holder to track IO operations. + * @return Number of bytes written. + * @throws IgniteCheckedException If failed. + */ + private int writeLargeFragments(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + if (row.size() < MIN_SIZE_FOR_DATA_PAGE) + return 0; + + // Write large row fragments. + int written = 0; + + do { + long pageId = reuseList == this ? + takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); + + AbstractDataPageIO initIo = null; + + if (pageId == 0L) { + pageId = allocateDataPage(row.partition()); + + initIo = row.ioVersions().latest(); + } + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) + pageId = initReusedPage(row, pageId, statHolder); + else + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); + + written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); + + assert written != FAIL_I; // We can't fail here. + + memMetrics.incrementLargeEntriesPages(); + } + while (written != COMPLETE && (row.size() - written) >= MIN_SIZE_FOR_DATA_PAGE); + + return written; } /** * @param reusedPageId Reused page id. - * @param partId Partition id. * @param statHolder Statistics holder to track IO operations. * @return Prepared page id. * * @see PagesList#initReusedPage(long, long, long, int, byte, PageIO) */ - private long initReusedPage(T row, long reusedPageId, int partId, - IoStatisticsHolder statHolder) throws IgniteCheckedException { + private long initReusedPage(T row, long reusedPageId, IoStatisticsHolder statHolder) throws IgniteCheckedException { long reusedPage = acquirePage(reusedPageId, statHolder); try { long reusedPageAddr = writeLock(reusedPageId, reusedPage); @@ -546,7 +729,7 @@ private long initReusedPage(T row, long reusedPageId, int partId, try { return initReusedPage(reusedPageId, reusedPage, reusedPageAddr, - partId, PageIdAllocator.FLAG_DATA, row.ioVersions().latest()); + row.partition(), PageIdAllocator.FLAG_DATA, row.ioVersions().latest()); } finally { writeUnlock(reusedPageId, reusedPage, reusedPageAddr, true); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java index e28d421bdf063c..b229fc450ff4f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence.freelist; +import java.util.Iterator; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.processors.cache.persistence.Storable; @@ -32,6 +33,12 @@ public interface FreeList { */ public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException; + /** + * @param iter Rows iterator. + * @throws IgniteCheckedException If failed. + */ + public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException; + /** * @param link Row link. * @param row New row data. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java index ff980af918c752..3fb7f1841eba23 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java @@ -282,15 +282,7 @@ public static R writePage( boolean ok = false; try { - if (init != null) { - // It is a new page and we have to initialize it. - doInitPage(pageMem, grpId, pageId, page, pageAddr, init, wal); - walPlc = FALSE; - } - else - init = PageIO.getPageIO(pageAddr); - - R res = h.run(grpId, pageId, page, pageAddr, init, walPlc, arg, intArg, statHolder); + R res = writePage(pageMem, grpId, pageId, page, pageAddr, lsnr, h, init, wal, walPlc, arg, intArg, statHolder); ok = true; @@ -309,6 +301,33 @@ public static R writePage( } } + public static R writePage( + PageMemory pageMem, + int grpId, + long pageId, + long page, + long pageAddr, + PageLockListener lsnr, + PageHandler h, + PageIO init, + IgniteWriteAheadLogManager wal, + Boolean walPlc, + X arg, + int intArg, + IoStatisticsHolder statHolder + ) throws IgniteCheckedException { + if (init != null) { + // It is a new page and we have to initialize it. + doInitPage(pageMem, grpId, pageId, page, pageAddr, init, wal); + walPlc = FALSE; + } + else + init = PageIO.getPageIO(pageAddr); + + return h.run(grpId, pageId, page, pageAddr, init, walPlc, arg, intArg, statHolder); + } + + /** * @param pageMem Page memory. * @param grpId Group ID. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java index 8d1ab878f2970d..f6900b8401ad6c 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java @@ -711,7 +711,8 @@ void recheckLock() { boolean preload, AffinityTopologyVersion topVer, GridDrType drType, - boolean fromStore + boolean fromStore, + CacheDataRow row ) throws IgniteCheckedException, GridCacheEntryRemovedException { assert false; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java new file mode 100644 index 00000000000000..a804181ea1bdc1 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java @@ -0,0 +1,351 @@ +/* + * 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.processors.cache.distributed.rebalancing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteDataStreamer; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.managers.communication.GridIoMessage; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage; +import org.apache.ignite.internal.util.typedef.PA; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteInClosure; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.spi.IgniteSpiException; +import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.WithSystemProperty; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.ignite.IgniteSystemProperties.IGNITE_BASELINE_AUTO_ADJUST_ENABLED; + +/** + * Measures time required for preloading data. + */ +public class PreloadingFlowTest extends GridCommonAbstractTest { + /** */ + private static final int CACHE_SIZE = 2_000_000; + + /** */ + private static final int ITERATIONS = 10; + + /** */ + private CountDownLatch preloadStartSync; + + /** */ + public CacheAtomicityMode cacheAtomicityMode; + + /** */ + public boolean persistenceEnabled; + + /** {@inheritDoc} */ + @Override protected long getTestTimeout() { + return TimeUnit.MINUTES.toMillis(30); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setDataStorageConfiguration(new DataStorageConfiguration(). + setDefaultDataRegionConfiguration(new DataRegionConfiguration() + .setPersistenceEnabled(persistenceEnabled))); + + cfg.setRebalanceThreadPoolSize(4); + + cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME) + .setCacheMode(CacheMode.REPLICATED) + .setAtomicityMode(cacheAtomicityMode) + .setRebalanceBatchesPrefetchCount(8)); + + boolean supplyNode = getTestIgniteInstanceIndex(igniteInstanceName) == 0; + + cfg.setCommunicationSpi(new TestCommunicationSpi(supplyNode ? preloadStartSync = new CountDownLatch(1) : null)); + + return cfg; + } + + /** + * + */ + @Before + public void setup() throws Exception { + cleanPersistenceDir(); + } + + /** + * + */ + @After + public void tearDown() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + } + + /** + * + */ + @Test + @WithSystemProperty(key = IGNITE_BASELINE_AUTO_ADJUST_ENABLED, value = "false") + public void measurePreloadTime() throws Exception { + List results = new ArrayList<>(); + + boolean[] persistenceModes = new boolean[] {false, true}; + + try { + for (boolean persistence : persistenceModes) { + persistenceEnabled = persistence; + + for (CacheAtomicityMode atomicity : CacheAtomicityMode.values()) { + cacheAtomicityMode = atomicity; + + long totalTime = 0; + + for (int i = 0; i < ITERATIONS; i++) { + long time = preload(CACHE_SIZE, i == 0); + + log.info("*** iter=" + i + ", persistence=" + persistence + + ", atomicity=" + atomicity + ", time=" + time); + + totalTime += time; + } + + results.add(String.format(" Average time: %d (persistence=%b, atomicity=%s)", + totalTime / ITERATIONS, persistenceEnabled, cacheAtomicityMode)); + } + } + } + finally { + log.info("*****************************************************************************************"); + + for (String result : results) + log.info(result); + + log.info("*****************************************************************************************"); + } + } + + /** + * + */ + private long preload(int size, boolean validateCacheAfterLoad) throws Exception { + long time; + + try { + Ignite node = startGrid(0); + + node.cluster().active(true); + + log.info("Load cache data."); + + Map data = prepare(size); + + loadCache(node, DEFAULT_CACHE_NAME, data); + + awaitPartitionMapExchange(); + + IgniteEx node2 = startGrid(1); + + node.cluster().setBaselineTopology(node2.cluster().nodes()); + + IgniteInternalCache cache = node2.cachex(DEFAULT_CACHE_NAME); + + boolean rebalanceStarted = GridTestUtils.waitForCondition(new PA() { + @Override public boolean apply() { + return !cache.context().preloader().rebalanceFuture().isDone(); + } + }, 10_000); + + assertTrue(rebalanceStarted); + + preloadStartSync.countDown(); + + IgniteInternalFuture fut = cache.context().preloader().rebalanceFuture(); + + long start = U.currentTimeMillis(); + + fut.get(30, TimeUnit.SECONDS); + + time = U.currentTimeMillis() - start; + + if (validateCacheAfterLoad) { + log.info("Validation."); + + stopGrid(0); + + awaitPartitionMapExchange(); + + node2.cache(DEFAULT_CACHE_NAME); + + for (Map.Entry e : data.entrySet()) + assertEquals(e.getValue(), cache.get(e.getKey())); + } + } + finally { + tearDown(); + } + + return time; + } + + /** + * @param cnt Count of entries. + * @return Preapred data. + */ + private Map prepare(int cnt) { + Map data = new LinkedHashMap<>(U.capacity(cnt)); + + byte[] bytes = new byte[50]; + + for (int i = 0; i < cnt; i++) + data.put(i, new TestObject("val-" + i, "version-" + i, i, i * Integer.MAX_VALUE, bytes)); + + return data; + } + + /** + * + */ + private void loadCache(Ignite node, String name, Map data) { + try (IgniteDataStreamer streamer = node.dataStreamer(name)) { + streamer.addData(data); + } + } + + /** + * + */ + private static class TestCommunicationSpi extends TcpCommunicationSpi { + /** */ + private final CountDownLatch latch; + + /** + * @param latch Preloading start latch. + */ + private TestCommunicationSpi(CountDownLatch latch) { + this.latch = latch; + } + + /** {@inheritDoc} */ + @Override public void sendMessage( + final ClusterNode node, + final Message msg, + final IgniteInClosure ackC + ) throws IgniteSpiException { + try { + boolean supplyMsg = msg instanceof GridIoMessage && + ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage; + + if (supplyMsg && latch != null) + U.await(latch, 10, TimeUnit.SECONDS); + + super.sendMessage(node, msg, ackC); + } + catch (IgniteInterruptedCheckedException e) { + throw new IgniteSpiException(e); + } + } + } + + /** + * Test object. + */ + public static class TestObject { + /** */ + private String field1; + + /** */ + private String field2; + + /** */ + private int field3; + + /** */ + private long field4; + + /** */ + private byte[] field5; + + /** + * Default constructor. + */ + public TestObject() { + // No-op. + } + + /** + * + */ + public TestObject(String field1, String field2, int field3, long field4, byte[] field5) { + this.field1 = field1; + this.field2 = field2; + this.field3 = field3; + this.field4 = field4; + this.field5 = field5; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + TestObject obj = (TestObject)o; + + return field3 == obj.field3 && + field4 == obj.field4 && + Objects.equals(field1, obj.field1) && + Objects.equals(field2, obj.field2) && + Arrays.equals(field5, obj.field5); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + int res = Objects.hash(field1, field2, field3, field4); + + res = 31 * res + Arrays.hashCode(field5); + + return res; + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java new file mode 100644 index 00000000000000..f22d14f7e3c123 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java @@ -0,0 +1,217 @@ +/* + * 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.processors.cache.persistence.pagemem; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.cache.Cache; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.managers.communication.GridIoMessage; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage; +import org.apache.ignite.internal.util.lang.GridCloseableIterator; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteInClosure; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.spi.IgniteSpiException; +import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.WithSystemProperty; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Check page memory consistency after preloading. + */ +@RunWith(Parameterized.class) +public class MemoryLeakAfterRebalanceSelfTest extends GridCommonAbstractTest { + /** */ + private final CountDownLatch preloadStartLatch = new CountDownLatch(1); + + /** */ + @Parameterized.Parameter + public CacheAtomicityMode cacheAtomicityMode; + + /** */ + @Parameterized.Parameters(name = " [atomicity={0}]") + public static Iterable parameters() { + return Arrays.asList(new Object[][] {{CacheAtomicityMode.ATOMIC}, {CacheAtomicityMode.TRANSACTIONAL}}); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setDataStorageConfiguration(new DataStorageConfiguration(). + setDefaultDataRegionConfiguration(new DataRegionConfiguration() + .setPersistenceEnabled(true))); + + cfg.setRebalanceThreadPoolSize(4); + + cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME) + .setAffinity(new RendezvousAffinityFunction(false, 16)) + .setCacheMode(CacheMode.REPLICATED) + .setAtomicityMode(cacheAtomicityMode)); + + boolean supplier = getTestIgniteInstanceIndex(igniteInstanceName) == 0; + + cfg.setCommunicationSpi(new TestCommunicationSpi(supplier ? preloadStartLatch : null)); + + return cfg; + } + + /** Initialization. */ + @Before + public void before() throws Exception { + cleanPersistenceDir(); + } + + /** Clean up. */ + @After + public void after() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + } + + /** + * @throws Exception If failed. + */ + @Test + @WithSystemProperty(key = IgniteSystemProperties.IGNITE_BASELINE_AUTO_ADJUST_ENABLED, value = "false") + public void testPreloadingWithConcurrentUpdates() throws Exception { + int size = GridTestUtils.SF.applyLB(500_000, 5_000); + + // Prepare data. + Map data = new HashMap<>(U.capacity(size)); + + for (int i = 0; i < size; i++) + data.put(i, i + " v.1"); + + // Start 1 node. + Ignite node = startGrid(0); + + node.cluster().active(true); + + // Load data. + node.cache(DEFAULT_CACHE_NAME).putAll(data); + + // Start 2 node. + IgniteEx node2 = startGrid(1); + + node.cluster().setBaselineTopology(node.cluster().nodes()); + + IgniteInternalCache cache = node2.cachex(DEFAULT_CACHE_NAME); + + // Simulate concurrent updates when preloading. + for (int i = 0; i < size; i += 10) { + String val = i + " v.2"; + + cache.put(i, val); + data.put(i, val); + + // Start preloading. + if (i > size / 2) + preloadStartLatch.countDown(); + } + + awaitPartitionMapExchange(); + + // Stop node 1. + stopGrid(0); + + awaitPartitionMapExchange(); + + assertEquals(data.size(), cache.size()); + + GridCacheContext cctx = cache.context(); + + // Ensure that there are no duplicate entries left on data pages in page memory. + try (GridCloseableIterator> itr = cctx.offheap().cacheEntriesIterator( + cctx, + true, + true, + cctx.topology().readyTopologyVersion(), + false, + null, + true)) { + + while (itr.hasNext()) { + Cache.Entry entry = itr.next(); + + Integer key = entry.getKey(); + + String exp = data.remove(key); + + assertEquals(exp, entry.getValue()); + } + } + + assertTrue(data.isEmpty()); + } + + /** */ + private static class TestCommunicationSpi extends TcpCommunicationSpi { + /** */ + private final CountDownLatch latch; + + /** */ + private TestCommunicationSpi(CountDownLatch latch) { + this.latch = latch; + } + + /** {@inheritDoc} */ + @Override public void sendMessage( + final ClusterNode node, + final Message msg, + final IgniteInClosure ackC + ) throws IgniteSpiException { + try { + boolean supplyMsg = msg instanceof GridIoMessage && + ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage; + + if (supplyMsg && latch != null) + U.await(latch, 10, TimeUnit.SECONDS); + + super.sendMessage(node, msg, ackC); + } catch (IgniteInterruptedCheckedException e) { + throw new IgniteSpiException(e); + } + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java index b4089e9e842bdc..7552bb66a9a454 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java @@ -18,9 +18,11 @@ package org.apache.ignite.internal.processors.database; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; @@ -65,6 +67,9 @@ public class CacheFreeListSelfTest extends GridCommonAbstractTest { /** */ private static final long MB = 1024L * 1024L; + /** */ + private static final int BATCH_SIZE = 100; + /** */ private PageMemory pageMem; @@ -118,6 +123,46 @@ public void testInsertDeleteSingleThreaded_16384() throws Exception { checkInsertDeleteSingleThreaded(16384); } + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_1024() throws Exception { + checkInsertDeleteMultiThreaded(1024, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_2048() throws Exception { + checkInsertDeleteMultiThreaded(2048, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_4096() throws Exception { + checkInsertDeleteMultiThreaded(4096, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_8192() throws Exception { + checkInsertDeleteMultiThreaded(8192, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_16384() throws Exception { + checkInsertDeleteMultiThreaded(16384, true); + } + /** * @throws Exception if failed. */ @@ -163,6 +208,15 @@ public void testInsertDeleteMultiThreaded_16384() throws Exception { * @throws Exception If failed. */ protected void checkInsertDeleteMultiThreaded(final int pageSize) throws Exception { + checkInsertDeleteMultiThreaded(pageSize, false); + } + + /** + * @param pageSize Page size. + * @param batched Batch mode flag. + * @throws Exception If failed. + */ + protected void checkInsertDeleteMultiThreaded(final int pageSize, boolean batched) throws Exception { final FreeList list = createFreeList(pageSize); Random rnd = new Random(); @@ -188,6 +242,8 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize) throws Excepti GridTestUtils.runMultiThreaded(new Callable() { @Override public Object call() throws Exception { + List rows = new ArrayList<>(BATCH_SIZE); + Random rnd = ThreadLocalRandom.current(); for (int i = 0; i < 200_000; i++) { @@ -218,16 +274,36 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize) throws Excepti TestDataRow row = new TestDataRow(keySize, valSize); - list.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); + if (batched) { + assert row.link() == 0; + rows.add(row); + } + else { + list.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); + + assertTrue(row.link() != 0L); + + TestDataRow old = stored.put(row.link(), row); - assertTrue(row.link() != 0L); + assertNull(old); + } + + if (rows.size() == BATCH_SIZE) { + list.insertDataRows(rows.iterator(), IoStatisticsHolderNoOp.INSTANCE); + + for (TestDataRow row0 : rows) { + assertTrue(row0.link() != 0L); - TestDataRow old = stored.put(row.link(), row); + TestDataRow old = stored.put(row0.link(), row0); - assertNull(old); + assertNull(old); + } + + rows.clear(); + } } else { - while (true) { + while (!stored.isEmpty()) { Iterator it = stored.values().iterator(); if (it.hasNext()) { diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsMvccTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsMvccTestSuite.java index 220c41ff9d6200..12efe5302489c1 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsMvccTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsMvccTestSuite.java @@ -35,6 +35,7 @@ import org.apache.ignite.internal.processors.cache.persistence.pagemem.BPlusTreeReuseListPageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.FillFactorMetricTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.IndexStoragePageMemoryImplTest; +import org.apache.ignite.internal.processors.cache.persistence.pagemem.MemoryLeakAfterRebalanceSelfTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplNoLoadTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryNoStoreLeakTest; @@ -83,6 +84,8 @@ public static List> suite() { ignoredTests.add(IgnitePdsDestroyCacheTest.class); ignoredTests.add(IgnitePdsDestroyCacheWithoutCheckpointsTest.class); + ignoredTests.add(MemoryLeakAfterRebalanceSelfTest.class); + return new ArrayList<>(IgnitePdsTestSuite.suite(ignoredTests)); } } diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java index f865bb8363967e..74e763b82c3781 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java @@ -42,6 +42,7 @@ import org.apache.ignite.internal.processors.cache.persistence.pagemem.BPlusTreeReuseListPageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.FillFactorMetricTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.IndexStoragePageMemoryImplTest; +import org.apache.ignite.internal.processors.cache.persistence.pagemem.MemoryLeakAfterRebalanceSelfTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplNoLoadTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryLazyAllocationTest; @@ -98,6 +99,8 @@ public static List> suite(Collection ignoredTests) { //GridTestUtils.addTestIfNeeded(suite, PageIdDistributionTest.class, ignoredTests); //GridTestUtils.addTestIfNeeded(suite, TrackingPageIOTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, MemoryLeakAfterRebalanceSelfTest.class, ignoredTests); + // BTree tests with store page memory. GridTestUtils.addTestIfNeeded(suite, BPlusTreePageMemoryImplTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, BPlusTreeReuseListPageMemoryImplTest.class, ignoredTests); From 74d70f272cd512b214f4b31dd4991655733e2176 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 27 May 2019 16:43:29 +0300 Subject: [PATCH 02/50] IGNITE-11584 Code cleanup. --- .../freelist/AbstractFreeList.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 7b1aa5a47150a3..ec7a1436387e6e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -473,7 +473,7 @@ private long allocateDataPage(int part) throws IgniteCheckedException { int remaining = row.size() - written; - long pageId = takePage(bucket(remaining, false) + 1, REUSE_BUCKET, row, statHolder); + long pageId = getPage(bucket(remaining, false) + 1, REUSE_BUCKET, row, statHolder); AbstractDataPageIO initIo = null; @@ -529,10 +529,12 @@ private long allocateDataPage(int part) throws IgniteCheckedException { try { T row = iter.next(); - int written = 0; + int written; - while (written != COMPLETE || row.link() == 0) { - if ((written = writeLargeFragments(row, statHolder)) == COMPLETE) { + do { + written = writeLargeFragments(row, statHolder); + + if (written == COMPLETE) { row = iter.hasNext() ? iter.next() : row; continue; @@ -544,7 +546,7 @@ private long allocateDataPage(int part) throws IgniteCheckedException { int minBucket = bucket(rowSize % MIN_SIZE_FOR_DATA_PAGE, false); - long pageId = takePage(REUSE_BUCKET - 1, minBucket, row, statHolder); + long pageId = getPage(REUSE_BUCKET - 1, minBucket, row, statHolder); if (pageId == 0) { pageId = allocateDataPage(row.partition()); @@ -599,7 +601,7 @@ private long allocateDataPage(int part) throws IgniteCheckedException { if (releaseAfterWrite) pageMem.releasePage(grpId, pageId, page); } - } + } while (written != COMPLETE || row.link() == 0); } catch (RuntimeException e) { throw new CorruptedFreeListException("Failed to insert data rows", e); @@ -607,23 +609,23 @@ private long allocateDataPage(int part) throws IgniteCheckedException { } /** - * Take page from freelist. + * Get a page from the free list. * - * @param from Start bucket. - * @param to Finish bucket. + * @param min Minimum bucket. + * @param max Maximum bucket. * @param row Row to process. * @param statHolder Statistics holder to track IO operations. * @return Page ID or {@code 0} if none available. * @throws IgniteCheckedException If failed. */ - private long takePage(int from, int to, T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + private long getPage(int min, int max, T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { long pageId = 0; - int partId = row.partition(); + int direction = min < max ? 1 : -1; - int direction = from < to ? 1 : -1; + for (int b = min; b != max; b += direction) { + assert b != REUSE_BUCKET; - for (int b = from; b != to; b += direction) { pageId = takeEmptyPage(b, row.ioVersions(), statHolder); if (pageId != 0L) @@ -639,16 +641,17 @@ private long takePage(int from, int to, T row, IoStatisticsHolder statHolder) th if (pageId == 0) return 0; - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + + if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. return initReusedPage(row, pageId, statHolder); - else // Page is taken from free space bucket. For in-memory mode partition must be changed. - return PageIdUtils.changePartitionId(pageId, partId); + else // For in-memory mode partition must be changed. + return PageIdUtils.changePartitionId(pageId, row.partition()); } /** - * Put page into freelist. + * Insert page into the free list. * - * @param freespace Page free space. + * @param freeSpace Page free space. * @param pageId Page ID. * @param page Page pointer. * @param pageAddr Page address. @@ -656,14 +659,14 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken * @throws IgniteCheckedException If failed. */ private void putPage( - int freespace, + int freeSpace, long pageId, long page, long pageAddr, IoStatisticsHolder statHolder ) throws IgniteCheckedException { - if (freespace > MIN_PAGE_FREE_SPACE) { - int bucket = bucket(freespace, false); + if (freeSpace > MIN_PAGE_FREE_SPACE) { + int bucket = bucket(freeSpace, false); put(null, pageId, page, pageAddr, bucket, statHolder); } From cc43474ff414f789e8fa4023929f2c233bb48c3f Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 28 May 2019 11:46:01 +0300 Subject: [PATCH 03/50] IGNITE-11584 Code cleanup. --- .../freelist/AbstractFreeList.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index ec7a1436387e6e..e928b7243a663a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -535,17 +535,17 @@ private long allocateDataPage(int part) throws IgniteCheckedException { written = writeLargeFragments(row, statHolder); if (written == COMPLETE) { - row = iter.hasNext() ? iter.next() : row; + if (iter.hasNext()) + row = iter.next(); continue; } AbstractDataPageIO initIo = null; - int rowSize = row.size(); - - int minBucket = bucket(rowSize % MIN_SIZE_FOR_DATA_PAGE, false); + int minBucket = bucket(row.size() % MIN_SIZE_FOR_DATA_PAGE, false); + // Search for the most free page with enough space. long pageId = getPage(REUSE_BUCKET - 1, minBucket, row, statHolder); if (pageId == 0) { @@ -569,24 +569,24 @@ private long allocateDataPage(int part) throws IgniteCheckedException { try { do { - boolean largeRow = rowSize > MIN_SIZE_FOR_DATA_PAGE; + if (row.link() == 0) + written = writeLargeFragments(row, statHolder); - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, - initIo, wal, null, row, largeRow ? written : 0, statHolder); + if (written != COMPLETE) { + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, + writeRow, initIo, wal, null, row, written, statHolder); + } assert written == COMPLETE : written; initIo = null; - while (iter.hasNext() && written == COMPLETE) { - row = iter.next(); - - written = writeLargeFragments(row, statHolder); - } + if (!iter.hasNext()) + break; - rowSize = row.size(); + row = iter.next(); } - while (iter.hasNext() && io.getFreeSpace(pageAddr) >= (rowSize % MIN_SIZE_FOR_DATA_PAGE)); + while (io.getFreeSpace(pageAddr) >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); ok = true; } From 36cb9ae1c983437e756eba379640722024046d97 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 28 May 2019 12:44:34 +0300 Subject: [PATCH 04/50] IGNITE-11584 Coode deduplication revert. --- .../freelist/AbstractFreeList.java | 205 +++++++++--------- 1 file changed, 98 insertions(+), 107 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index e928b7243a663a..b136bd805f7917 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -465,54 +465,85 @@ private long allocateDataPage(int part) throws IgniteCheckedException { /** {@inheritDoc} */ @Override public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + int rowSize = row.size(); + + int written = 0; + try { - int written = writeLargeFragments(row, statHolder); + do { + if (written != 0) + memMetrics.incrementLargeEntriesPages(); - if (written == COMPLETE) - return; + int remaining = rowSize - written; - int remaining = row.size() - written; + long pageId = 0L; - long pageId = getPage(bucket(remaining, false) + 1, REUSE_BUCKET, row, statHolder); + if (remaining < MIN_SIZE_FOR_DATA_PAGE) { + for (int b = bucket(remaining, false) + 1; b < BUCKETS - 1; b++) { + pageId = takeEmptyPage(b, row.ioVersions(), statHolder); - AbstractDataPageIO initIo = null; + if (pageId != 0L) + break; + } + } - if (pageId == 0L) { - pageId = allocateDataPage(row.partition()); + if (pageId == 0L) { // Handle reuse bucket. + if (reuseList == this) + pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); + else + pageId = reuseList.takeRecycledPage(); + } - initIo = row.ioVersions().latest(); - } + AbstractDataPageIO initIo = null; - long page = pageMem.acquirePage(grpId, pageId, statHolder); + if (pageId == 0L) { + pageId = allocateDataPage(row.partition()); - boolean releaseAfterWrite = true; + initIo = row.ioVersions().latest(); + } + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + pageId = initReusedPage(row, pageId, statHolder); + else // Page is taken from free space bucket. For in-memory mode partition must be changed. + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - try { - long pageAddr = writeLock(pageId, page); + long page = acquirePage(pageId, statHolder); - assert pageAddr != 0; + try { + long pageAddr = writeLock(pageId, page); - AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); + assert pageAddr != 0; - boolean ok = false; + boolean ok = false; - try { - PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, initIo, wal, - null, row, written, statHolder); + try { + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, initIo, wal, + null, row, written, statHolder); - ok = true; - } - finally { - putPage(io.getFreeSpace(pageAddr), pageId, page, pageAddr, statHolder); + assert written != FAIL_I; // We can't fail here. + + int freeSpace = row.ioVersions().latest().getFreeSpace(pageAddr); + + // Put page into free list if needed. + if (freeSpace > MIN_PAGE_FREE_SPACE) { + int bucket = bucket(freeSpace, false); + + put(null, pageId, page, pageAddr, bucket, statHolder); + } + + assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 + + ok = true; + } + finally { + assert writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); - if (releaseAfterWrite = writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0)) writeUnlock(pageId, page, pageAddr, ok); + } } - } - finally { - if (releaseAfterWrite) - pageMem.releasePage(grpId, pageId, page); - } + finally { + releasePage(pageId, page); + } + } while (written != COMPLETE); } catch (IgniteCheckedException | Error e) { throw e; @@ -543,27 +574,44 @@ private long allocateDataPage(int part) throws IgniteCheckedException { AbstractDataPageIO initIo = null; + long pageId = 0; + + // Search for the most free page with enough free space. int minBucket = bucket(row.size() % MIN_SIZE_FOR_DATA_PAGE, false); - // Search for the most free page with enough space. - long pageId = getPage(REUSE_BUCKET - 1, minBucket, row, statHolder); + for (int b = REUSE_BUCKET - 1; b != minBucket; b--) { + pageId = takeEmptyPage(b, row.ioVersions(), statHolder); + + if (pageId != 0L) + break; + } + + if (pageId == 0) { + if (reuseList == this) + pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); + else + pageId = reuseList.takeRecycledPage(); + } if (pageId == 0) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } + else + if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + pageId = initReusedPage(row, pageId, statHolder); + else // For in-memory mode partition must be changed. + pageId = PageIdUtils.changePartitionId(pageId, row.partition()); - long page = pageMem.acquirePage(grpId, pageId, statHolder); - - boolean releaseAfterWrite = true; + long page = acquirePage(pageId, statHolder); try { long pageAddr = writeLock(pageId, page); assert pageAddr != 0; - AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); + AbstractDataPageIO io = row.ioVersions().latest(); boolean ok = false; @@ -588,18 +636,27 @@ private long allocateDataPage(int part) throws IgniteCheckedException { } while (io.getFreeSpace(pageAddr) >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); + int freeSpace = io.getFreeSpace(pageAddr); + + // Put page into free list if needed. + if (freeSpace > MIN_PAGE_FREE_SPACE) { + int bucket = bucket(freeSpace, false); + + put(null, pageId, page, pageAddr, bucket, statHolder); + } + + assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 + ok = true; } finally { - putPage(io.getFreeSpace(pageAddr), pageId, page, pageAddr, statHolder); + assert writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); - if (releaseAfterWrite = writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0)) - writeUnlock(pageId, page, pageAddr, ok); + writeUnlock(pageId, page, pageAddr, ok); } } finally { - if (releaseAfterWrite) - pageMem.releasePage(grpId, pageId, page); + releasePage(pageId, page); } } while (written != COMPLETE || row.link() == 0); } @@ -608,72 +665,6 @@ private long allocateDataPage(int part) throws IgniteCheckedException { } } - /** - * Get a page from the free list. - * - * @param min Minimum bucket. - * @param max Maximum bucket. - * @param row Row to process. - * @param statHolder Statistics holder to track IO operations. - * @return Page ID or {@code 0} if none available. - * @throws IgniteCheckedException If failed. - */ - private long getPage(int min, int max, T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - long pageId = 0; - - int direction = min < max ? 1 : -1; - - for (int b = min; b != max; b += direction) { - assert b != REUSE_BUCKET; - - pageId = takeEmptyPage(b, row.ioVersions(), statHolder); - - if (pageId != 0L) - break; - } - - if (pageId == 0) { - if (reuseList == this) - pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); - else - pageId = reuseList.takeRecycledPage(); - } - - if (pageId == 0) - return 0; - - if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. - return initReusedPage(row, pageId, statHolder); - else // For in-memory mode partition must be changed. - return PageIdUtils.changePartitionId(pageId, row.partition()); - } - - /** - * Insert page into the free list. - * - * @param freeSpace Page free space. - * @param pageId Page ID. - * @param page Page pointer. - * @param pageAddr Page address. - * @param statHolder Statistics holder to track IO operations. - * @throws IgniteCheckedException If failed. - */ - private void putPage( - int freeSpace, - long pageId, - long page, - long pageAddr, - IoStatisticsHolder statHolder - ) throws IgniteCheckedException { - if (freeSpace > MIN_PAGE_FREE_SPACE) { - int bucket = bucket(freeSpace, false); - - put(null, pageId, page, pageAddr, bucket, statHolder); - } - - assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 - } - /** * Write fragments of the row, which occupy the whole memory page. * From 46ba49ffe93bc767f9bab10562df6d860ead64ab Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 28 May 2019 16:43:00 +0300 Subject: [PATCH 05/50] IGNITE-11584 Code cleanup. --- .../freelist/AbstractFreeList.java | 99 +++++++++---------- .../persistence/tree/util/PageHandler.java | 20 +++- 2 files changed, 65 insertions(+), 54 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index b136bd805f7917..c51b7672809c7a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -131,13 +131,27 @@ private final class UpdateRowHandler extends PageHandler { } } - /** */ - private final PageHandler writeRow = new WriteRowHandler(); + /** Write handler which puts memory page into the free list after an update. */ + private final PageHandler writeRow = new WriteRowHandler(true); + + /** Write handler which doesn't put memory page into the free list after an update. */ + private final PageHandler writeRowNoPut = new WriteRowHandler(false); /** * */ private final class WriteRowHandler extends PageHandler { + /** */ + private final boolean putPageIntoFreeList; + + /** + * @param putPageIntoFreeList Put page into the free list after an update. + */ + WriteRowHandler(boolean putPageIntoFreeList) { + this.putPageIntoFreeList = putPageIntoFreeList; + } + + /** {@inheritDoc} */ @Override public Integer run( int cacheId, long pageId, @@ -160,6 +174,17 @@ private final class WriteRowHandler extends PageHandler { written = (written == 0 && oldFreeSpace >= rowSize) ? addRow(pageId, page, pageAddr, io, row, rowSize) : addRowFragment(pageId, page, pageAddr, io, row, written, rowSize); + if (putPageIntoFreeList) { + // Reread free space after update. + int newFreeSpace = io.getFreeSpace(pageAddr); + + if (newFreeSpace > MIN_PAGE_FREE_SPACE) { + int bucket = bucket(newFreeSpace, false); + + put(null, pageId, page, pageAddr, bucket, statHolder); + } + } + if (written == rowSize) evictionTracker.touchPage(pageId); @@ -506,44 +531,11 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken else // Page is taken from free space bucket. For in-memory mode partition must be changed. pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - long page = acquirePage(pageId, statHolder); - - try { - long pageAddr = writeLock(pageId, page); - - assert pageAddr != 0; - - boolean ok = false; - - try { - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRow, initIo, wal, - null, row, written, statHolder); - - assert written != FAIL_I; // We can't fail here. - - int freeSpace = row.ioVersions().latest().getFreeSpace(pageAddr); - - // Put page into free list if needed. - if (freeSpace > MIN_PAGE_FREE_SPACE) { - int bucket = bucket(freeSpace, false); - - put(null, pageId, page, pageAddr, bucket, statHolder); - } - - assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 + written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); - ok = true; - } - finally { - assert writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); - - writeUnlock(pageId, page, pageAddr, ok); - } - } - finally { - releasePage(pageId, page); - } - } while (written != COMPLETE); + assert written != FAIL_I; // We can't fail here. + } + while (written != COMPLETE); } catch (IgniteCheckedException | Error e) { throw e; @@ -565,6 +557,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken do { written = writeLargeFragments(row, statHolder); + // If there is no remainder - go to the next row. if (written == COMPLETE) { if (iter.hasNext()) row = iter.next(); @@ -572,12 +565,10 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken continue; } - AbstractDataPageIO initIo = null; - long pageId = 0; - // Search for the most free page with enough free space. - int minBucket = bucket(row.size() % MIN_SIZE_FOR_DATA_PAGE, false); + // Search for the most free page with enough space. + int minBucket = bucket(row.size() - written, false); for (int b = REUSE_BUCKET - 1; b != minBucket; b--) { pageId = takeEmptyPage(b, row.ioVersions(), statHolder); @@ -593,17 +584,19 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken pageId = reuseList.takeRecycledPage(); } + AbstractDataPageIO initIo = null; + if (pageId == 0) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } - else - if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. pageId = initReusedPage(row, pageId, statHolder); else // For in-memory mode partition must be changed. pageId = PageIdUtils.changePartitionId(pageId, row.partition()); + // Lock page. long page = acquirePage(pageId, statHolder); try { @@ -616,19 +609,20 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken boolean ok = false; try { + // Fill the page up to the end. do { if (row.link() == 0) written = writeLargeFragments(row, statHolder); if (written != COMPLETE) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, - writeRow, initIo, wal, null, row, written, statHolder); + writeRowNoPut, initIo, wal, null, row, written, statHolder); + + initIo = null; } assert written == COMPLETE : written; - initIo = null; - if (!iter.hasNext()) break; @@ -638,7 +632,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int freeSpace = io.getFreeSpace(pageAddr); - // Put page into free list if needed. + // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { int bucket = bucket(freeSpace, false); @@ -650,7 +644,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken ok = true; } finally { - assert writeRow.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); + assert writeRowNoPut.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); writeUnlock(pageId, page, pageAddr, ok); } @@ -658,7 +652,8 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken finally { releasePage(pageId, page); } - } while (written != COMPLETE || row.link() == 0); + } + while (written != COMPLETE || row.link() == 0); } catch (RuntimeException e) { throw new CorruptedFreeListException("Failed to insert data rows", e); @@ -696,7 +691,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) else pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); + written = write(pageId, writeRowNoPut, initIo, row, written, FAIL_I, statHolder); assert written != FAIL_I; // We can't fail here. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java index 3fb7f1841eba23..07158243d3e3c3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java @@ -282,7 +282,8 @@ public static R writePage( boolean ok = false; try { - R res = writePage(pageMem, grpId, pageId, page, pageAddr, lsnr, h, init, wal, walPlc, arg, intArg, statHolder); + R res = writePage( + pageMem, grpId, pageId, page, pageAddr, lsnr, h, init, wal, walPlc, arg, intArg, statHolder); ok = true; @@ -301,6 +302,22 @@ public static R writePage( } } + /** + * @param pageMem Page memory. + * @param grpId Group ID. + * @param pageId Page ID. + * @param pageAddr Page address. + * @param lsnr Lock listener. + * @param h Handler. + * @param init IO for new page initialization or {@code null} if it is an existing page. + * @param wal Write ahead log. + * @param walPlc Full page WAL record policy. + * @param arg Argument. + * @param intArg Argument of type {@code int}. + * @param statHolder Statistics holder to track IO operations. + * @return Handler result. + * @throws IgniteCheckedException If failed. + */ public static R writePage( PageMemory pageMem, int grpId, @@ -327,7 +344,6 @@ public static R writePage( return h.run(grpId, pageId, page, pageAddr, init, walPlc, arg, intArg, statHolder); } - /** * @param pageMem Page memory. * @param grpId Group ID. From 57942b191b07972c6369467254fa11dc6250cd78 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Thu, 30 May 2019 16:54:48 +0300 Subject: [PATCH 06/50] IGNITE-11584 Reuse list only. --- .../freelist/AbstractFreeList.java | 89 ++++++++----------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index c51b7672809c7a..89cb481b233746 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -552,37 +552,10 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken try { T row = iter.next(); - int written; + int written = 0; - do { - written = writeLargeFragments(row, statHolder); - - // If there is no remainder - go to the next row. - if (written == COMPLETE) { - if (iter.hasNext()) - row = iter.next(); - - continue; - } - - long pageId = 0; - - // Search for the most free page with enough space. - int minBucket = bucket(row.size() - written, false); - - for (int b = REUSE_BUCKET - 1; b != minBucket; b--) { - pageId = takeEmptyPage(b, row.ioVersions(), statHolder); - - if (pageId != 0L) - break; - } - - if (pageId == 0) { - if (reuseList == this) - pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); - else - pageId = reuseList.takeRecycledPage(); - } + while (written != COMPLETE || row.link() == 0) { + long pageId = takeReusedPage(row, statHolder); AbstractDataPageIO initIo = null; @@ -591,12 +564,8 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken initIo = row.ioVersions().latest(); } - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. - pageId = initReusedPage(row, pageId, statHolder); - else // For in-memory mode partition must be changed. - pageId = PageIdUtils.changePartitionId(pageId, row.partition()); - // Lock page. + // Acquire and lock page. long page = acquirePage(pageId, statHolder); try { @@ -609,9 +578,11 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken boolean ok = false; try { + int freeSpace; + // Fill the page up to the end. do { - if (row.link() == 0) + if (row.link() == 0 && initIo == null && row.size() >= MIN_SIZE_FOR_DATA_PAGE) written = writeLargeFragments(row, statHolder); if (written != COMPLETE) { @@ -621,16 +592,16 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken initIo = null; } - assert written == COMPLETE : written; + freeSpace = io.getFreeSpace(pageAddr); - if (!iter.hasNext()) + if (written != COMPLETE || !iter.hasNext()) break; row = iter.next(); - } - while (io.getFreeSpace(pageAddr) >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); - int freeSpace = io.getFreeSpace(pageAddr); + written = 0; + } + while (freeSpace != 0 && freeSpace >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { @@ -653,7 +624,6 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken releasePage(pageId, page); } } - while (written != COMPLETE || row.link() == 0); } catch (RuntimeException e) { throw new CorruptedFreeListException("Failed to insert data rows", e); @@ -669,27 +639,18 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken * @throws IgniteCheckedException If failed. */ private int writeLargeFragments(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (row.size() < MIN_SIZE_FOR_DATA_PAGE) - return 0; - - // Write large row fragments. int written = 0; do { - long pageId = reuseList == this ? - takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); + long pageId = takeReusedPage(row, statHolder); AbstractDataPageIO initIo = null; - if (pageId == 0L) { + if (pageId == 0) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) - pageId = initReusedPage(row, pageId, statHolder); - else - pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); written = write(pageId, writeRowNoPut, initIo, row, written, FAIL_I, statHolder); @@ -702,6 +663,28 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) return written; } + /** + * Get a page from reuse bucket of the free list. + * + * @param row Row. + * @param statHolder Statistics holder to track IO operations. + * @return Page ID or {@code 0} if none available. + * @throws IgniteCheckedException If failed. + */ + private long takeReusedPage(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + long pageId = reuseList == this ? + takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); + + if (pageId != 0L) { + if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) + pageId = initReusedPage(row, pageId, statHolder); + else + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); + } + + return pageId; + } + /** * @param reusedPageId Reused page id. * @param statHolder Statistics holder to track IO operations. From 15ad82e37da36984d819bf17ffa4082cc4b871ba Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Thu, 30 May 2019 17:45:57 +0300 Subject: [PATCH 07/50] IGNITE-11584 Code cleanup. --- .../persistence/freelist/AbstractFreeList.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 89cb481b233746..a6ec4286f54844 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -578,12 +578,12 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken boolean ok = false; try { - int freeSpace; + int freeSpace = 0; // Fill the page up to the end. do { - if (row.link() == 0 && initIo == null && row.size() >= MIN_SIZE_FOR_DATA_PAGE) - written = writeLargeFragments(row, statHolder); + if (freeSpace != 0 && row.size() >= MIN_SIZE_FOR_DATA_PAGE) + written = writeWholePages(row, statHolder); if (written != COMPLETE) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, @@ -635,10 +635,12 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken * * @param row Row to process. * @param statHolder Statistics holder to track IO operations. - * @return Number of bytes written. + * @return Number of bytes written, {@link #COMPLETE} if the row was fully written. * @throws IgniteCheckedException If failed. */ - private int writeLargeFragments(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + assert row.link() == 0 : row.link(); + int written = 0; do { @@ -658,7 +660,7 @@ private int writeLargeFragments(T row, IoStatisticsHolder statHolder) throws Ign memMetrics.incrementLargeEntriesPages(); } - while (written != COMPLETE && (row.size() - written) >= MIN_SIZE_FOR_DATA_PAGE); + while (row.size() - written >= MIN_SIZE_FOR_DATA_PAGE); return written; } From 18bd5637a52c06c3741ec26b9c7ab30b73e2c03c Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 11:03:45 +0300 Subject: [PATCH 08/50] IGNITE-11584 Comments. --- .../cache/persistence/freelist/AbstractFreeList.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index a6ec4286f54844..e8ca63397c8959 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -582,9 +582,11 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken // Fill the page up to the end. do { + // Current page isn't empty and the data row is large - write large parts on separate pages. if (freeSpace != 0 && row.size() >= MIN_SIZE_FOR_DATA_PAGE) written = writeWholePages(row, statHolder); + // Use the current page if it's empty or the row is small (also for the tail of a large row). if (written != COMPLETE) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRowNoPut, initIo, wal, null, row, written, statHolder); @@ -594,6 +596,8 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken freeSpace = io.getFreeSpace(pageAddr); + assert freeSpace == 0 || written == COMPLETE; + if (written != COMPLETE || !iter.hasNext()) break; From d8a6f7f5353d63dc5dbdaf744422862a506d5bd8 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 12:45:52 +0300 Subject: [PATCH 09/50] IGNITE-11584 Code cleanup. --- .../cache/persistence/freelist/AbstractFreeList.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index e8ca63397c8959..58244f092c273a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -547,14 +547,15 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken /** {@inheritDoc} */ @Override public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException { - assert iter.hasNext(); + if (!iter.hasNext()) + return; try { T row = iter.next(); int written = 0; - while (written != COMPLETE || row.link() == 0) { + while (written != COMPLETE || iter.hasNext()) { long pageId = takeReusedPage(row, statHolder); AbstractDataPageIO initIo = null; From 9cacb18075bbeb95c944cb6675bf40f25293b0d2 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 15:13:22 +0300 Subject: [PATCH 10/50] IGNITE-11584 wip --- .../freelist/AbstractFreeList.java | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 58244f092c273a..9b9c2b9c21e5ae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -556,6 +556,15 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int written = 0; while (written != COMPLETE || iter.hasNext()) { + written = writeWholePages(row, statHolder); + + if (written == COMPLETE) { + if (iter.hasNext()) + row = iter.next(); + + continue; + } + long pageId = takeReusedPage(row, statHolder); AbstractDataPageIO initIo = null; @@ -574,39 +583,37 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken assert pageAddr != 0; - AbstractDataPageIO io = row.ioVersions().latest(); + AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); - boolean ok = false; + boolean dirty = false; try { - int freeSpace = 0; - // Fill the page up to the end. do { - // Current page isn't empty and the data row is large - write large parts on separate pages. - if (freeSpace != 0 && row.size() >= MIN_SIZE_FOR_DATA_PAGE) + if (written == 0) written = writeWholePages(row, statHolder); - // Use the current page if it's empty or the row is small (also for the tail of a large row). if (written != COMPLETE) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, writeRowNoPut, initIo, wal, null, row, written, statHolder); initIo = null; - } - freeSpace = io.getFreeSpace(pageAddr); + dirty = true; + } - assert freeSpace == 0 || written == COMPLETE; + assert written == COMPLETE; - if (written != COMPLETE || !iter.hasNext()) + if (!iter.hasNext()) break; row = iter.next(); written = 0; } - while (freeSpace != 0 && freeSpace >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); + while (io.getFreeSpace(pageAddr) >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); + + int freeSpace = io.getFreeSpace(pageAddr); // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { @@ -616,13 +623,11 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 - - ok = true; } finally { assert writeRowNoPut.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); - writeUnlock(pageId, page, pageAddr, ok); + writeUnlock(pageId, page, pageAddr, dirty); } } finally { @@ -644,6 +649,9 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken * @throws IgniteCheckedException If failed. */ private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + if (row.size() < MIN_SIZE_FOR_DATA_PAGE) + return 0; + assert row.link() == 0 : row.link(); int written = 0; From b10171e1d256610b1ff831bec007b6a33643bc21 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 19:00:11 +0300 Subject: [PATCH 11/50] wip exp --- .../freelist/AbstractFreeList.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 9b9c2b9c21e5ae..cc45d289e27739 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -555,13 +555,16 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int written = 0; - while (written != COMPLETE || iter.hasNext()) { + while (iter.hasNext() || written != COMPLETE) { written = writeWholePages(row, statHolder); if (written == COMPLETE) { - if (iter.hasNext()) + if (iter.hasNext()) { row = iter.next(); + written = 0; + } + continue; } @@ -589,7 +592,16 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken try { // Fill the page up to the end. - do { + while (iter.hasNext() || written != COMPLETE) { + if (written == COMPLETE) { + row = iter.next(); + + written = 0; + + if (io.getFreeSpace(pageAddr) < (row.size() % MIN_SIZE_FOR_DATA_PAGE)) + break; + } + if (written == 0) written = writeWholePages(row, statHolder); @@ -603,15 +615,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } assert written == COMPLETE; - - if (!iter.hasNext()) - break; - - row = iter.next(); - - written = 0; } - while (io.getFreeSpace(pageAddr) >= (row.size() % MIN_SIZE_FOR_DATA_PAGE)); int freeSpace = io.getFreeSpace(pageAddr); From ff2d5401617d0d3a3f390b9da267f8bdf1e1243d Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 19:03:19 +0300 Subject: [PATCH 12/50] wip exp link --- .../cache/persistence/freelist/AbstractFreeList.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index cc45d289e27739..9c076c82659009 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -555,16 +555,13 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int written = 0; - while (iter.hasNext() || written != COMPLETE) { + while (iter.hasNext() || row.link() == 0) { written = writeWholePages(row, statHolder); if (written == COMPLETE) { - if (iter.hasNext()) { + if (iter.hasNext()) row = iter.next(); - written = 0; - } - continue; } From 0fef23cdeb03d6f638606adfe764d38fd145ab75 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 31 May 2019 19:09:42 +0300 Subject: [PATCH 13/50] wip exp link removed --- .../persistence/freelist/AbstractFreeList.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 9c076c82659009..bdb09235c9ab6d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -547,23 +547,17 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken /** {@inheritDoc} */ @Override public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (!iter.hasNext()) - return; - try { - T row = iter.next(); - - int written = 0; + T row = null; - while (iter.hasNext() || row.link() == 0) { - written = writeWholePages(row, statHolder); + int written = COMPLETE; - if (written == COMPLETE) { - if (iter.hasNext()) - row = iter.next(); + while (iter.hasNext() || written != COMPLETE) { + if (written == COMPLETE) + row = iter.next(); + if ((written = writeWholePages(row, statHolder)) == COMPLETE) continue; - } long pageId = takeReusedPage(row, statHolder); From 569af20c65ee75289cbb23a0cb11cc72da65e5eb Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 3 Jun 2019 11:59:05 +0300 Subject: [PATCH 14/50] IGNITE-11584 Rework. --- .../freelist/AbstractFreeList.java | 128 ++++++------------ 1 file changed, 42 insertions(+), 86 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index bdb09235c9ab6d..ce4a3330c7d468 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -547,27 +547,47 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken /** {@inheritDoc} */ @Override public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException { + if (!iter.hasNext()) + return; + try { - T row = null; + T row = iter.next(); - int written = COMPLETE; + int written = 0; while (iter.hasNext() || written != COMPLETE) { - if (written == COMPLETE) - row = iter.next(); + long pageId = 0L; - if ((written = writeWholePages(row, statHolder)) == COMPLETE) - continue; + int remaining = row.size() - written; + + if (remaining > 0 && remaining < MIN_SIZE_FOR_DATA_PAGE) { + // Search for the most free page with enough space. + for (int b = bucket(remaining, false) + 1; b < REUSE_BUCKET; b++) { + pageId = takeEmptyPage(b, row.ioVersions(), statHolder); - long pageId = takeReusedPage(row, statHolder); + if (pageId != 0L) + break; + } + } + + if (pageId == 0L) { // Handle reuse bucket. + if (reuseList == this) + pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); + else + pageId = reuseList.takeRecycledPage(); + } AbstractDataPageIO initIo = null; - if (pageId == 0) { + if (pageId == 0L) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + pageId = initReusedPage(row, pageId, statHolder); + else // Page is taken from free space bucket. For in-memory mode partition must be changed. + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); // Acquire and lock page. long page = acquirePage(pageId, statHolder); @@ -582,33 +602,29 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken boolean dirty = false; try { + int freeSpace; + // Fill the page up to the end. - while (iter.hasNext() || written != COMPLETE) { - if (written == COMPLETE) { - row = iter.next(); + do { + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, + writeRowNoPut, initIo, wal, null, row, written, statHolder); - written = 0; + dirty = true; - if (io.getFreeSpace(pageAddr) < (row.size() % MIN_SIZE_FOR_DATA_PAGE)) - break; - } + initIo = null; - if (written == 0) - written = writeWholePages(row, statHolder); + freeSpace = io.getFreeSpace(pageAddr); - if (written != COMPLETE) { - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, - writeRowNoPut, initIo, wal, null, row, written, statHolder); + assert freeSpace == 0 || written == COMPLETE; - initIo = null; + if (written != COMPLETE || !iter.hasNext()) + break; - dirty = true; - } + row = iter.next(); - assert written == COMPLETE; + written = 0; } - - int freeSpace = io.getFreeSpace(pageAddr); + while (freeSpace > 0 && (freeSpace >= row.size() || row.size() > MIN_SIZE_FOR_DATA_PAGE)); // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { @@ -635,66 +651,6 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } } - /** - * Write fragments of the row, which occupy the whole memory page. - * - * @param row Row to process. - * @param statHolder Statistics holder to track IO operations. - * @return Number of bytes written, {@link #COMPLETE} if the row was fully written. - * @throws IgniteCheckedException If failed. - */ - private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (row.size() < MIN_SIZE_FOR_DATA_PAGE) - return 0; - - assert row.link() == 0 : row.link(); - - int written = 0; - - do { - long pageId = takeReusedPage(row, statHolder); - - AbstractDataPageIO initIo = null; - - if (pageId == 0) { - pageId = allocateDataPage(row.partition()); - - initIo = row.ioVersions().latest(); - } - - written = write(pageId, writeRowNoPut, initIo, row, written, FAIL_I, statHolder); - - assert written != FAIL_I; // We can't fail here. - - memMetrics.incrementLargeEntriesPages(); - } - while (row.size() - written >= MIN_SIZE_FOR_DATA_PAGE); - - return written; - } - - /** - * Get a page from reuse bucket of the free list. - * - * @param row Row. - * @param statHolder Statistics holder to track IO operations. - * @return Page ID or {@code 0} if none available. - * @throws IgniteCheckedException If failed. - */ - private long takeReusedPage(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - long pageId = reuseList == this ? - takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); - - if (pageId != 0L) { - if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) - pageId = initReusedPage(row, pageId, statHolder); - else - pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - } - - return pageId; - } - /** * @param reusedPageId Reused page id. * @param statHolder Statistics holder to track IO operations. From 8f0db69c42571049a1410ac96bdebb2542d31e12 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 4 Jun 2019 12:58:59 +0300 Subject: [PATCH 15/50] IGNITE-11584 Don't break into more parts. --- .../persistence/freelist/AbstractFreeList.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index ce4a3330c7d468..ebc5951ba3e273 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -504,7 +504,7 @@ private long allocateDataPage(int part) throws IgniteCheckedException { long pageId = 0L; if (remaining < MIN_SIZE_FOR_DATA_PAGE) { - for (int b = bucket(remaining, false) + 1; b < BUCKETS - 1; b++) { + for (int b = bucket(remaining, false) + 1; b < REUSE_BUCKET; b++) { pageId = takeEmptyPage(b, row.ioVersions(), statHolder); if (pageId != 0L) @@ -555,13 +555,12 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int written = 0; - while (iter.hasNext() || written != COMPLETE) { - long pageId = 0L; - + do { int remaining = row.size() - written; + long pageId = 0L; + if (remaining > 0 && remaining < MIN_SIZE_FOR_DATA_PAGE) { - // Search for the most free page with enough space. for (int b = bucket(remaining, false) + 1; b < REUSE_BUCKET; b++) { pageId = takeEmptyPage(b, row.ioVersions(), statHolder); @@ -615,8 +614,6 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken freeSpace = io.getFreeSpace(pageAddr); - assert freeSpace == 0 || written == COMPLETE; - if (written != COMPLETE || !iter.hasNext()) break; @@ -624,7 +621,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken written = 0; } - while (freeSpace > 0 && (freeSpace >= row.size() || row.size() > MIN_SIZE_FOR_DATA_PAGE)); + while (freeSpace != 0 && freeSpace >= row.size() % MIN_SIZE_FOR_DATA_PAGE); // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { @@ -644,7 +641,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken finally { releasePage(pageId, page); } - } + } while (written != COMPLETE || iter.hasNext()); } catch (RuntimeException e) { throw new CorruptedFreeListException("Failed to insert data rows", e); @@ -652,6 +649,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } /** + * @param row Row. * @param reusedPageId Reused page id. * @param statHolder Statistics holder to track IO operations. * @return Prepared page id. From 81d7d76a14cbdc779a1bdcf43f3584b65ca867a0 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 4 Jun 2019 16:09:09 +0300 Subject: [PATCH 16/50] IGNITE-11584 Code cleanup. --- .../cache/persistence/RowStore.java | 2 +- .../freelist/AbstractFreeList.java | 28 +++++++++++++------ .../cache/persistence/freelist/FreeList.java | 6 ++-- .../database/CacheFreeListSelfTest.java | 6 ++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java index 93d962489728e3..3edc917dd23bf1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java @@ -125,7 +125,7 @@ public void addRow(CacheDataRow row, IoStatisticsHolder statHolder) throws Ignit public void addRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); - freeList.insertDataRows(rows.iterator(), statHolder); + freeList.insertDataRows(rows, statHolder); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index ebc5951ba3e273..e3727d07ab8d14 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence.freelist; +import java.util.Collection; import java.util.Iterator; import java.util.concurrent.atomic.AtomicReferenceArray; import org.apache.ignite.IgniteCheckedException; @@ -135,7 +136,7 @@ private final class UpdateRowHandler extends PageHandler { private final PageHandler writeRow = new WriteRowHandler(true); /** Write handler which doesn't put memory page into the free list after an update. */ - private final PageHandler writeRowNoPut = new WriteRowHandler(false); + private final PageHandler writeRowKeepPage = new WriteRowHandler(false); /** * @@ -546,11 +547,14 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } /** {@inheritDoc} */ - @Override public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (!iter.hasNext()) + @Override public void insertDataRows(Collection rows, + IoStatisticsHolder statHolder) throws IgniteCheckedException { + if (rows.isEmpty()) return; try { + Iterator iter = rows.iterator(); + T row = iter.next(); int written = 0; @@ -596,7 +600,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken assert pageAddr != 0; - AbstractDataPageIO io = initIo != null ? initIo : PageIO.getPageIO(pageAddr); + AbstractDataPageIO io = initIo == null ? PageIO.getPageIO(pageAddr) : initIo; boolean dirty = false; @@ -604,9 +608,9 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int freeSpace; // Fill the page up to the end. - do { + while (true) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, - writeRowNoPut, initIo, wal, null, row, written, statHolder); + writeRowKeepPage, initIo, wal, null, row, written, statHolder); dirty = true; @@ -614,14 +618,21 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken freeSpace = io.getFreeSpace(pageAddr); + assert freeSpace == 0 || written == COMPLETE; + if (written != COMPLETE || !iter.hasNext()) break; row = iter.next(); written = 0; + + int alignedSize = row.size() > MIN_SIZE_FOR_DATA_PAGE ? + row.size() % MIN_SIZE_FOR_DATA_PAGE : row.size(); + + if (freeSpace < alignedSize || alignedSize == 0) + break; } - while (freeSpace != 0 && freeSpace >= row.size() % MIN_SIZE_FOR_DATA_PAGE); // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { @@ -633,7 +644,8 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 } finally { - assert writeRowNoPut.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); + // Should always unlock data page after write. + assert writeRowKeepPage.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); writeUnlock(pageId, page, pageAddr, dirty); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java index b229fc450ff4f0..894c1aa64faca0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java @@ -17,7 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence.freelist; -import java.util.Iterator; +import java.util.Collection; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.processors.cache.persistence.Storable; @@ -34,10 +34,10 @@ public interface FreeList { public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException; /** - * @param iter Rows iterator. + * @param rows Rows. * @throws IgniteCheckedException If failed. */ - public void insertDataRows(Iterator iter, IoStatisticsHolder statHolder) throws IgniteCheckedException; + public void insertDataRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException; /** * @param link Row link. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java index 7552bb66a9a454..9970d59430365b 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java @@ -274,10 +274,8 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize, boolean batche TestDataRow row = new TestDataRow(keySize, valSize); - if (batched) { - assert row.link() == 0; + if (batched) rows.add(row); - } else { list.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); @@ -289,7 +287,7 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize, boolean batche } if (rows.size() == BATCH_SIZE) { - list.insertDataRows(rows.iterator(), IoStatisticsHolderNoOp.INSTANCE); + list.insertDataRows(rows, IoStatisticsHolderNoOp.INSTANCE); for (TestDataRow row0 : rows) { assertTrue(row0.link() != 0L); From 6dd61bce2e1b4a8272d2ef43b53412c89725ced2 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 5 Jun 2019 15:40:14 +0300 Subject: [PATCH 17/50] IGNITE-11584 Removed flow-test, added benchmark. --- .../pagemem/JmhCacheFreelistBenchmark.java | 297 +++++++++++++++ .../rebalancing/PreloadingFlowTest.java | 351 ------------------ 2 files changed, 297 insertions(+), 351 deletions(-) create mode 100644 modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java delete mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java new file mode 100644 index 00000000000000..7493423fddb413 --- /dev/null +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java @@ -0,0 +1,297 @@ +/* + * 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.benchmarks.jmh.pagemem; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteLogger; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider; +import org.apache.ignite.internal.pagemem.PageIdAllocator; +import org.apache.ignite.internal.pagemem.PageMemory; +import org.apache.ignite.internal.pagemem.impl.PageMemoryNoStoreImpl; +import org.apache.ignite.internal.processors.cache.CacheObjectImpl; +import org.apache.ignite.internal.processors.cache.KeyCacheObjectImpl; +import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; +import org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter; +import org.apache.ignite.internal.processors.cache.persistence.DataRegion; +import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl; +import org.apache.ignite.internal.processors.cache.persistence.Storable; +import org.apache.ignite.internal.processors.cache.persistence.evict.NoOpPageEvictionTracker; +import org.apache.ignite.internal.processors.cache.persistence.freelist.CacheFreeListImpl; +import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.stat.IoStatisticsHolder; +import org.apache.ignite.internal.stat.IoStatisticsHolderNoOp; +import org.apache.ignite.logger.java.JavaLogger; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import static java.util.concurrent.TimeUnit.MICROSECONDS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +/** + * Performance comparision between FreeList.insertRow(..) and FreeList.insertRows(..). + */ +@BenchmarkMode(Mode.AverageTime) +@Fork(value = 1, jvmArgsAppend = {"-Xms1g", "-server", "-XX:+AggressiveOpts", "-XX:MaxMetaspaceSize=256m", "-ea"}) +@OutputTimeUnit(MICROSECONDS) +@State(Scope.Benchmark) +@Threads(1) +@Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS) +@Measurement(iterations = 11, time = 200, timeUnit = MILLISECONDS) +public class JmhCacheFreelistBenchmark { + /** */ + private static final long MEMORY_REGION_SIZE = 10 * 1024 * 1024 * 1024L; // 10 GB + + /** */ + private static final int PAGE_SIZE = 4096; + + /** */ + private static final int ROWS_COUNT = 200; + + /** */ + public enum DATA_ROW_SIZE { + /** */ + r4_64(4, 64), + + /** */ + r100_300(100, 300), + + /** */ + r300_700(300, 700), + + /** */ + r700_1200(700, 1200), + + /** */ + r1200_3000(1_200, 3_000), + + /** */ + r1000_8000(1_000, 8_000), + + /** Large objects only. */ + r4000_16000(4_000, 16_000), + + /** Mixed objects, mostly large objects. */ + r100_32000(100, 32_000); + + /** */ + private final int min; + + /** */ + private final int max; + + /** */ + DATA_ROW_SIZE(int min, int max) { + this.min = min; + this.max = max; + } + } + + /** + * Check {@link FreeList#insertDataRow(Storable, IoStatisticsHolder)} performance. + */ + @Benchmark + public void insertRow(FreeListProvider provider, Data rows) throws IgniteCheckedException { + for (CacheDataRow row : rows) + provider.freeList.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); + } + + /** + * Check {@link FreeList#insertDataRows(Collection, IoStatisticsHolder)} performance. + */ + @Benchmark + public void insertRows(FreeListProvider provider, Data rows) throws IgniteCheckedException { + provider.freeList.insertDataRows(rows, IoStatisticsHolderNoOp.INSTANCE); + } + + /** */ + @State(Scope.Thread) + public static class Data extends AbstractCollection { + /** */ + @Param + private DATA_ROW_SIZE range; + + /** */ + private Collection rows = new ArrayList<>(ROWS_COUNT); + + /** */ + @Setup(Level.Iteration) + public void prepare() { + Random rnd = ThreadLocalRandom.current(); + + int randomRange = range.max - range.min; + + for (int i = 0; i < ROWS_COUNT; i++) { + int keySize = (range.min + rnd.nextInt(randomRange)) / 2; + int valSize = (range.min + rnd.nextInt(randomRange)) / 2; + + CacheDataRow row = new TestDataRow(keySize, valSize); + + rows.add(row); + } + } + + /** */ + @TearDown(Level.Iteration) + public void cleanup() { + rows.clear(); + } + + /** {@inheritDoc} */ + @Override public Iterator iterator() { + return rows.iterator(); + } + + /** {@inheritDoc} */ + @Override public int size() { + return rows.size(); + } + } + + /** */ + @State(Scope.Thread) + public static class FreeListProvider { + /** */ + private final DataRegionConfiguration plcCfg = + new DataRegionConfiguration().setInitialSize(MEMORY_REGION_SIZE).setMaxSize(MEMORY_REGION_SIZE); + + /** */ + private final JavaLogger log = new JavaLogger(); + + /** */ + private PageMemory pageMem; + + /** */ + private FreeList freeList; + + /** */ + @Setup(Level.Trial) + public void setup() throws IgniteCheckedException { + pageMem = createPageMemory(log, PAGE_SIZE, plcCfg); + + freeList = createFreeList(pageMem, plcCfg); + } + + /** */ + @TearDown(Level.Trial) + public void tearDown() { + pageMem.stop(true); + } + + /** + * @return Page memory. + */ + protected PageMemory createPageMemory(IgniteLogger log, int pageSize, DataRegionConfiguration plcCfg) { + PageMemory pageMem = new PageMemoryNoStoreImpl(log, + new UnsafeMemoryProvider(log), + null, + pageSize, + plcCfg, + new DataRegionMetricsImpl(plcCfg), + true); + + pageMem.start(); + + return pageMem; + } + + /** + * @param pageMem Page memory. + * @return Free list. + * @throws IgniteCheckedException If failed. + */ + private FreeList createFreeList( + PageMemory pageMem, + DataRegionConfiguration plcCfg + ) throws IgniteCheckedException { + long metaPageId = pageMem.allocatePage(1, 1, PageIdAllocator.FLAG_DATA); + + DataRegionMetricsImpl regionMetrics = new DataRegionMetricsImpl(plcCfg); + + DataRegion dataRegion = new DataRegion(pageMem, plcCfg, regionMetrics, new NoOpPageEvictionTracker()); + + return new CacheFreeListImpl(1, "freelist", regionMetrics, dataRegion, null, + null, metaPageId, true); + } + } + + /** */ + private static class TestDataRow extends CacheDataRowAdapter { + /** */ + private long link; + + /** + * @param keySize Key size. + * @param valSize Value size. + */ + private TestDataRow(int keySize, int valSize) { + super( + new KeyCacheObjectImpl(0, new byte[keySize], 0), + new CacheObjectImpl(0, new byte[valSize]), + new GridCacheVersion(keySize, valSize, 1), + 0 + ); + } + + /** {@inheritDoc} */ + @Override public long link() { + return link; + } + + /** {@inheritDoc} */ + @Override public void link(long link) { + this.link = link; + } + } + + /** + * Run benchmark. + * + * @param args Args. + */ + public static void main(String[] args) throws RunnerException { + final Options options = new OptionsBuilder() + .include(JmhCacheFreelistBenchmark.class.getSimpleName()) + .build(); + + new Runner(options).run(); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java deleted file mode 100644 index a804181ea1bdc1..00000000000000 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/PreloadingFlowTest.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * 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.processors.cache.distributed.rebalancing; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteDataStreamer; -import org.apache.ignite.IgniteException; -import org.apache.ignite.cache.CacheAtomicityMode; -import org.apache.ignite.cache.CacheMode; -import org.apache.ignite.cluster.ClusterNode; -import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.configuration.DataRegionConfiguration; -import org.apache.ignite.configuration.DataStorageConfiguration; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.internal.IgniteEx; -import org.apache.ignite.internal.IgniteInternalFuture; -import org.apache.ignite.internal.IgniteInterruptedCheckedException; -import org.apache.ignite.internal.managers.communication.GridIoMessage; -import org.apache.ignite.internal.processors.cache.IgniteInternalCache; -import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage; -import org.apache.ignite.internal.util.typedef.PA; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.lang.IgniteInClosure; -import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.spi.IgniteSpiException; -import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; -import org.apache.ignite.testframework.GridTestUtils; -import org.apache.ignite.testframework.junits.WithSystemProperty; -import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.apache.ignite.IgniteSystemProperties.IGNITE_BASELINE_AUTO_ADJUST_ENABLED; - -/** - * Measures time required for preloading data. - */ -public class PreloadingFlowTest extends GridCommonAbstractTest { - /** */ - private static final int CACHE_SIZE = 2_000_000; - - /** */ - private static final int ITERATIONS = 10; - - /** */ - private CountDownLatch preloadStartSync; - - /** */ - public CacheAtomicityMode cacheAtomicityMode; - - /** */ - public boolean persistenceEnabled; - - /** {@inheritDoc} */ - @Override protected long getTestTimeout() { - return TimeUnit.MINUTES.toMillis(30); - } - - /** {@inheritDoc} */ - @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { - IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - - cfg.setDataStorageConfiguration(new DataStorageConfiguration(). - setDefaultDataRegionConfiguration(new DataRegionConfiguration() - .setPersistenceEnabled(persistenceEnabled))); - - cfg.setRebalanceThreadPoolSize(4); - - cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME) - .setCacheMode(CacheMode.REPLICATED) - .setAtomicityMode(cacheAtomicityMode) - .setRebalanceBatchesPrefetchCount(8)); - - boolean supplyNode = getTestIgniteInstanceIndex(igniteInstanceName) == 0; - - cfg.setCommunicationSpi(new TestCommunicationSpi(supplyNode ? preloadStartSync = new CountDownLatch(1) : null)); - - return cfg; - } - - /** - * - */ - @Before - public void setup() throws Exception { - cleanPersistenceDir(); - } - - /** - * - */ - @After - public void tearDown() throws Exception { - stopAllGrids(); - - cleanPersistenceDir(); - } - - /** - * - */ - @Test - @WithSystemProperty(key = IGNITE_BASELINE_AUTO_ADJUST_ENABLED, value = "false") - public void measurePreloadTime() throws Exception { - List results = new ArrayList<>(); - - boolean[] persistenceModes = new boolean[] {false, true}; - - try { - for (boolean persistence : persistenceModes) { - persistenceEnabled = persistence; - - for (CacheAtomicityMode atomicity : CacheAtomicityMode.values()) { - cacheAtomicityMode = atomicity; - - long totalTime = 0; - - for (int i = 0; i < ITERATIONS; i++) { - long time = preload(CACHE_SIZE, i == 0); - - log.info("*** iter=" + i + ", persistence=" + persistence + - ", atomicity=" + atomicity + ", time=" + time); - - totalTime += time; - } - - results.add(String.format(" Average time: %d (persistence=%b, atomicity=%s)", - totalTime / ITERATIONS, persistenceEnabled, cacheAtomicityMode)); - } - } - } - finally { - log.info("*****************************************************************************************"); - - for (String result : results) - log.info(result); - - log.info("*****************************************************************************************"); - } - } - - /** - * - */ - private long preload(int size, boolean validateCacheAfterLoad) throws Exception { - long time; - - try { - Ignite node = startGrid(0); - - node.cluster().active(true); - - log.info("Load cache data."); - - Map data = prepare(size); - - loadCache(node, DEFAULT_CACHE_NAME, data); - - awaitPartitionMapExchange(); - - IgniteEx node2 = startGrid(1); - - node.cluster().setBaselineTopology(node2.cluster().nodes()); - - IgniteInternalCache cache = node2.cachex(DEFAULT_CACHE_NAME); - - boolean rebalanceStarted = GridTestUtils.waitForCondition(new PA() { - @Override public boolean apply() { - return !cache.context().preloader().rebalanceFuture().isDone(); - } - }, 10_000); - - assertTrue(rebalanceStarted); - - preloadStartSync.countDown(); - - IgniteInternalFuture fut = cache.context().preloader().rebalanceFuture(); - - long start = U.currentTimeMillis(); - - fut.get(30, TimeUnit.SECONDS); - - time = U.currentTimeMillis() - start; - - if (validateCacheAfterLoad) { - log.info("Validation."); - - stopGrid(0); - - awaitPartitionMapExchange(); - - node2.cache(DEFAULT_CACHE_NAME); - - for (Map.Entry e : data.entrySet()) - assertEquals(e.getValue(), cache.get(e.getKey())); - } - } - finally { - tearDown(); - } - - return time; - } - - /** - * @param cnt Count of entries. - * @return Preapred data. - */ - private Map prepare(int cnt) { - Map data = new LinkedHashMap<>(U.capacity(cnt)); - - byte[] bytes = new byte[50]; - - for (int i = 0; i < cnt; i++) - data.put(i, new TestObject("val-" + i, "version-" + i, i, i * Integer.MAX_VALUE, bytes)); - - return data; - } - - /** - * - */ - private void loadCache(Ignite node, String name, Map data) { - try (IgniteDataStreamer streamer = node.dataStreamer(name)) { - streamer.addData(data); - } - } - - /** - * - */ - private static class TestCommunicationSpi extends TcpCommunicationSpi { - /** */ - private final CountDownLatch latch; - - /** - * @param latch Preloading start latch. - */ - private TestCommunicationSpi(CountDownLatch latch) { - this.latch = latch; - } - - /** {@inheritDoc} */ - @Override public void sendMessage( - final ClusterNode node, - final Message msg, - final IgniteInClosure ackC - ) throws IgniteSpiException { - try { - boolean supplyMsg = msg instanceof GridIoMessage && - ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage; - - if (supplyMsg && latch != null) - U.await(latch, 10, TimeUnit.SECONDS); - - super.sendMessage(node, msg, ackC); - } - catch (IgniteInterruptedCheckedException e) { - throw new IgniteSpiException(e); - } - } - } - - /** - * Test object. - */ - public static class TestObject { - /** */ - private String field1; - - /** */ - private String field2; - - /** */ - private int field3; - - /** */ - private long field4; - - /** */ - private byte[] field5; - - /** - * Default constructor. - */ - public TestObject() { - // No-op. - } - - /** - * - */ - public TestObject(String field1, String field2, int field3, long field4, byte[] field5) { - this.field1 = field1; - this.field2 = field2; - this.field3 = field3; - this.field4 = field4; - this.field5 = field5; - } - - /** {@inheritDoc} */ - @Override public boolean equals(Object o) { - if (this == o) - return true; - - if (o == null || getClass() != o.getClass()) - return false; - - TestObject obj = (TestObject)o; - - return field3 == obj.field3 && - field4 == obj.field4 && - Objects.equals(field1, obj.field1) && - Objects.equals(field2, obj.field2) && - Arrays.equals(field5, obj.field5); - } - - /** {@inheritDoc} */ - @Override public int hashCode() { - int res = Objects.hash(field1, field2, field3, field4); - - res = 31 * res + Arrays.hashCode(field5); - - return res; - } - } -} From 52e7a4cdb9855e207fed273f23f14801621c3099 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 5 Jun 2019 16:52:40 +0300 Subject: [PATCH 18/50] IGNITE-11584 Fixed cacheId on data page. --- .../processors/cache/IgniteCacheOffheapManagerImpl.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index b15e71ce8fd49f..faf0e595c30c16 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1718,7 +1718,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo assert !cctx.mvccEnabled(); - int cacheId = cctx.group().storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; + int cacheId = grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; IoStatisticsHolder statHolder = grp.statisticsHolderData(); @@ -1737,11 +1737,6 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } rowStore().addRows(rows, statHolder); - - if (grp.sharedGroup() && !cctx.group().storeCacheIdInDataPage()) { - for (CacheDataRow row : rows) - ((DataRow)row).cacheId(cctx.cacheId()); - } } finally { busyLock.leaveBusy(); From 8366a235900baee004617f676761b599aa8d746c Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 5 Jun 2019 17:30:47 +0300 Subject: [PATCH 19/50] IGNITE-11584 Minor. --- .../preloader/GridDhtPartitionDemander.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 7f7b1613004100..0e9e1d6af78610 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -95,7 +95,7 @@ * Thread pool for requesting partitions from other nodes and populating local cache. */ public class GridDhtPartitionDemander { - /** */ + /** The maximum number of entries that can be preloaded between checkpoints. */ private static final int CHECKPOINT_THRESHOLD = 100; /** */ @@ -775,7 +775,7 @@ public void handleSupplyMessage( boolean last = supplyMsg.last().containsKey(p); - boolean batched = evictionAllowsBatch(grp.dataRegion(), supplyMsg.messageSize()); + boolean batched = canStoreWithoutEvictions(supplyMsg.messageSize()); if (part.state() == MOVING) { boolean reserved = part.reserve(); @@ -872,21 +872,21 @@ public void handleSupplyMessage( } /** - * @param region Memory region. - * @param msgSize Rebalance message size. - * @return {@code True} if entries could processed in batch. + * @param size Data size. + * @return {@code True} if rebalanced cache group allows writing a specified amount of data without evictions. */ - private boolean evictionAllowsBatch(DataRegion region, int msgSize) { - DataRegionConfiguration plc = region.config(); + private boolean canStoreWithoutEvictions(int size) { + DataRegionConfiguration plc = grp.dataRegion().config(); if (plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) return true; - PageMemory pageMem = region.pageMemory(); + PageMemory pageMem = grp.dataRegion().pageMemory(); int sysPageSize = pageMem.systemPageSize(); - int pagesRequired = (msgSize / sysPageSize) * 2; + // The number of pages is calculated taking into account memory fragmentation and possible concurrent updates. + int pagesRequired = (size / sysPageSize) * 2; long maxPages = plc.getMaxSize() / sysPageSize; From 4e7a863b82b52c6626fe23ab7bd6508fcb3d686a Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 5 Jun 2019 19:05:37 +0300 Subject: [PATCH 20/50] Revert "IGNITE-11584 Fixed cacheId on data page." This reverts commit c07e4822 --- .../processors/cache/IgniteCacheOffheapManagerImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index faf0e595c30c16..b15e71ce8fd49f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1718,7 +1718,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo assert !cctx.mvccEnabled(); - int cacheId = grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; + int cacheId = cctx.group().storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; IoStatisticsHolder statHolder = grp.statisticsHolderData(); @@ -1737,6 +1737,11 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } rowStore().addRows(rows, statHolder); + + if (grp.sharedGroup() && !cctx.group().storeCacheIdInDataPage()) { + for (CacheDataRow row : rows) + ((DataRow)row).cacheId(cctx.cacheId()); + } } finally { busyLock.leaveBusy(); From 882eb0780169cb5848c9a94c961c436c28a3042a Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Thu, 6 Jun 2019 19:54:44 +0300 Subject: [PATCH 21/50] IGNITE-11584 Fixed eviction tracker bug by reverting advanced code. --- .../pagemem/JmhCacheFreelistBenchmark.java | 4 +- .../freelist/AbstractFreeList.java | 126 +++++++++++++----- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java index 7493423fddb413..013f63ba485f2a 100644 --- a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java @@ -153,7 +153,7 @@ public static class Data extends AbstractCollection { private Collection rows = new ArrayList<>(ROWS_COUNT); /** */ - @Setup(Level.Iteration) + @Setup(Level.Invocation) public void prepare() { Random rnd = ThreadLocalRandom.current(); @@ -170,7 +170,7 @@ public void prepare() { } /** */ - @TearDown(Level.Iteration) + @TearDown(Level.Invocation) public void cleanup() { rows.clear(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index e3727d07ab8d14..dac6b0195940bb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -555,11 +555,17 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken try { Iterator iter = rows.iterator(); - T row = iter.next(); + T row = null; - int written = 0; + int written = COMPLETE; + + while (iter.hasNext() || written != COMPLETE) { + if (written == COMPLETE) + row = iter.next(); + + if ((written = writeWholePages(row, statHolder)) == COMPLETE) + continue; - do { int remaining = row.size() - written; long pageId = 0L; @@ -573,24 +579,17 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } } - if (pageId == 0L) { // Handle reuse bucket. - if (reuseList == this) - pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); - else - pageId = reuseList.takeRecycledPage(); - } + + if (pageId == 0) + pageId = takeReusedPage(row, statHolder); AbstractDataPageIO initIo = null; - if (pageId == 0L) { + if (pageId == 0) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. - pageId = initReusedPage(row, pageId, statHolder); - else // Page is taken from free space bucket. For in-memory mode partition must be changed. - pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); // Acquire and lock page. long page = acquirePage(pageId, statHolder); @@ -605,35 +604,34 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken boolean dirty = false; try { - int freeSpace; - // Fill the page up to the end. - while (true) { - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, - writeRowKeepPage, initIo, wal, null, row, written, statHolder); - - dirty = true; + while (iter.hasNext() || written != COMPLETE) { + if (written == COMPLETE) { + row = iter.next(); - initIo = null; + written = 0; - freeSpace = io.getFreeSpace(pageAddr); + if (io.getFreeSpace(pageAddr) < (row.size() % MIN_SIZE_FOR_DATA_PAGE)) + break; + } - assert freeSpace == 0 || written == COMPLETE; + if (written == 0) + written = writeWholePages(row, statHolder); - if (written != COMPLETE || !iter.hasNext()) - break; + if (written != COMPLETE) { + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, + writeRowKeepPage, initIo, wal, null, row, written, statHolder); - row = iter.next(); + initIo = null; - written = 0; + dirty = true; + } - int alignedSize = row.size() > MIN_SIZE_FOR_DATA_PAGE ? - row.size() % MIN_SIZE_FOR_DATA_PAGE : row.size(); - - if (freeSpace < alignedSize || alignedSize == 0) - break; + assert written == COMPLETE; } + int freeSpace = io.getFreeSpace(pageAddr); + // Put page into the free list if needed. if (freeSpace > MIN_PAGE_FREE_SPACE) { int bucket = bucket(freeSpace, false); @@ -653,13 +651,73 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken finally { releasePage(pageId, page); } - } while (written != COMPLETE || iter.hasNext()); + } } catch (RuntimeException e) { throw new CorruptedFreeListException("Failed to insert data rows", e); } } + /** + * Write fragments of the row, which occupy the whole memory page. + * + * @param row Row to process. + * @param statHolder Statistics holder to track IO operations. + * @return Number of bytes written, {@link #COMPLETE} if the row was fully written. + * @throws IgniteCheckedException If failed. + */ + private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + if (row.size() < MIN_SIZE_FOR_DATA_PAGE) + return 0; + + assert row.link() == 0 : row.link(); + + int written = 0; + + do { + long pageId = takeReusedPage(row, statHolder); + + AbstractDataPageIO initIo = null; + + if (pageId == 0) { + pageId = allocateDataPage(row.partition()); + + initIo = row.ioVersions().latest(); + } + + written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); + + assert written != FAIL_I; // We can't fail here. + + memMetrics.incrementLargeEntriesPages(); + } + while (row.size() - written >= MIN_SIZE_FOR_DATA_PAGE); + + return written; + } + + /** + * Get a page from reuse bucket of the free list. + * + * @param row Row. + * @param statHolder Statistics holder to track IO operations. + * @return Page ID or {@code 0} if none available. + * @throws IgniteCheckedException If failed. + */ + private long takeReusedPage(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { + long pageId = reuseList == this ? + takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); + + if (pageId != 0L) { + if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) + pageId = initReusedPage(row, pageId, statHolder); + else + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); + } + + return pageId; + } + /** * @param row Row. * @param reusedPageId Reused page id. From ca476f4291e96bdb17547a3ebbe40269aa2b85c3 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 7 Jun 2019 11:10:27 +0300 Subject: [PATCH 22/50] IGNITE-11584 Fix after rebase. --- .../freelist/AbstractFreeList.java | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index dac6b0195940bb..23e9f135cc13bf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -579,17 +579,24 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } } - - if (pageId == 0) - pageId = takeReusedPage(row, statHolder); + if (pageId == 0L) { // Handle reuse bucket. + if (reuseList == this) + pageId = takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder); + else + pageId = reuseList.takeRecycledPage(); + } AbstractDataPageIO initIo = null; - if (pageId == 0) { + if (pageId == 0L) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + pageId = initReusedPage(row, pageId, statHolder); + else // Page is taken from free space bucket. For in-memory mode partition must be changed. + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); // Acquire and lock page. long page = acquirePage(pageId, statHolder); @@ -619,7 +626,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken written = writeWholePages(row, statHolder); if (written != COMPLETE) { - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, this, + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, lockLsnr, writeRowKeepPage, initIo, wal, null, row, written, statHolder); initIo = null; @@ -675,15 +682,20 @@ private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteC int written = 0; do { - long pageId = takeReusedPage(row, statHolder); + long pageId = reuseList == this ? takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : + reuseList.takeRecycledPage(); AbstractDataPageIO initIo = null; - if (pageId == 0) { + if (pageId == 0L) { pageId = allocateDataPage(row.partition()); initIo = row.ioVersions().latest(); } + else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken from reuse bucket. + pageId = initReusedPage(row, pageId, statHolder); + else // Page is taken from free space bucket. For in-memory mode partition must be changed. + pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); written = write(pageId, writeRow, initIo, row, written, FAIL_I, statHolder); @@ -696,28 +708,6 @@ private int writeWholePages(T row, IoStatisticsHolder statHolder) throws IgniteC return written; } - /** - * Get a page from reuse bucket of the free list. - * - * @param row Row. - * @param statHolder Statistics holder to track IO operations. - * @return Page ID or {@code 0} if none available. - * @throws IgniteCheckedException If failed. - */ - private long takeReusedPage(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - long pageId = reuseList == this ? - takeEmptyPage(REUSE_BUCKET, row.ioVersions(), statHolder) : reuseList.takeRecycledPage(); - - if (pageId != 0L) { - if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) - pageId = initReusedPage(row, pageId, statHolder); - else - pageId = PageIdUtils.changePartitionId(pageId, (row.partition())); - } - - return pageId; - } - /** * @param row Row. * @param reusedPageId Reused page id. From 76d0bb4b0fd7038d5e9baa926f92d3778cd841e5 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 7 Jun 2019 15:22:33 +0300 Subject: [PATCH 23/50] IGNITE-11584 Bench fix after merge. --- .../jmh/pagemem/JmhCacheFreelistBenchmark.java | 15 ++++++++++++--- .../persistence/freelist/AbstractFreeList.java | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java index 013f63ba485f2a..4f656494e1fa73 100644 --- a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/pagemem/JmhCacheFreelistBenchmark.java @@ -38,7 +38,7 @@ import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl; import org.apache.ignite.internal.processors.cache.persistence.Storable; import org.apache.ignite.internal.processors.cache.persistence.evict.NoOpPageEvictionTracker; -import org.apache.ignite.internal.processors.cache.persistence.freelist.CacheFreeListImpl; +import org.apache.ignite.internal.processors.cache.persistence.freelist.CacheFreeList; import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.stat.IoStatisticsHolder; @@ -248,8 +248,17 @@ private FreeList createFreeList( DataRegion dataRegion = new DataRegion(pageMem, plcCfg, regionMetrics, new NoOpPageEvictionTracker()); - return new CacheFreeListImpl(1, "freelist", regionMetrics, dataRegion, null, - null, metaPageId, true); + return new CacheFreeList( + 1, + "freelist", + regionMetrics, + dataRegion, + null, + null, + metaPageId, + true, + null + ); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 23e9f135cc13bf..fee582e3de4504 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -649,7 +649,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480 } finally { - // Should always unlock data page after write. + // Should always unlock data page after an update. assert writeRowKeepPage.releaseAfterWrite(grpId, pageId, page, pageAddr, row, 0); writeUnlock(pageId, page, pageAddr, dirty); From f1603615913b02ef833d009abb3cc56688e4a274 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 7 Jun 2019 16:40:15 +0300 Subject: [PATCH 24/50] IGNITE-11584 Code cleanup. --- .../cache/persistence/freelist/AbstractFreeList.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index fee582e3de4504..7a676056bab5c4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -563,7 +563,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken if (written == COMPLETE) row = iter.next(); - if ((written = writeWholePages(row, statHolder)) == COMPLETE) + if (row.link() == 0 && (written = writeWholePages(row, statHolder)) == COMPLETE) continue; int remaining = row.size() - written; @@ -616,15 +616,12 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken if (written == COMPLETE) { row = iter.next(); - written = 0; + written = writeWholePages(row, statHolder); - if (io.getFreeSpace(pageAddr) < (row.size() % MIN_SIZE_FOR_DATA_PAGE)) + if (written != COMPLETE && io.getFreeSpace(pageAddr) < row.size() - written) break; } - if (written == 0) - written = writeWholePages(row, statHolder); - if (written != COMPLETE) { written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, lockLsnr, writeRowKeepPage, initIo, wal, null, row, written, statHolder); From b44d96af24ddd07663e7a9697609fadba3f0b289 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 7 Jun 2019 16:56:06 +0300 Subject: [PATCH 25/50] IGNITE-11584 Code cleanup 2. --- .../preloader/GridDhtPartitionDemander.java | 1 - .../freelist/AbstractFreeList.java | 29 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 0e9e1d6af78610..8644a364e397c9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -62,7 +62,6 @@ import org.apache.ignite.internal.processors.cache.mvcc.MvccVersionAware; import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxState; import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; -import org.apache.ignite.internal.processors.cache.persistence.DataRegion; import org.apache.ignite.internal.processors.cache.persistence.RowStore; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 7a676056bab5c4..f81a92a9a8b3de 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -549,9 +549,6 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken /** {@inheritDoc} */ @Override public void insertDataRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (rows.isEmpty()) - return; - try { Iterator iter = rows.iterator(); @@ -560,17 +557,19 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken int written = COMPLETE; while (iter.hasNext() || written != COMPLETE) { - if (written == COMPLETE) + if (written == COMPLETE) { row = iter.next(); - if (row.link() == 0 && (written = writeWholePages(row, statHolder)) == COMPLETE) - continue; + // If the data row was completely written without remainder, proceed to the next. + if ((written = writeWholePages(row, statHolder)) == COMPLETE) + continue; + } int remaining = row.size() - written; long pageId = 0L; - if (remaining > 0 && remaining < MIN_SIZE_FOR_DATA_PAGE) { + if (remaining < MIN_SIZE_FOR_DATA_PAGE) { for (int b = bucket(remaining, false) + 1; b < REUSE_BUCKET; b++) { pageId = takeEmptyPage(b, row.ioVersions(), statHolder); @@ -616,20 +615,20 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken if (written == COMPLETE) { row = iter.next(); - written = writeWholePages(row, statHolder); + // If the data row was completely written without remainder, proceed to the next. + if ((written = writeWholePages(row, statHolder)) == COMPLETE) + continue; - if (written != COMPLETE && io.getFreeSpace(pageAddr) < row.size() - written) + if (io.getFreeSpace(pageAddr) < row.size() - written) break; } - if (written != COMPLETE) { - written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, lockLsnr, - writeRowKeepPage, initIo, wal, null, row, written, statHolder); + written = PageHandler.writePage(pageMem, grpId, pageId, page, pageAddr, lockLsnr, + writeRowKeepPage, initIo, wal, null, row, written, statHolder); - initIo = null; + initIo = null; - dirty = true; - } + dirty = true; assert written == COMPLETE; } From 024361a06bba56eb5a6fde42ea1ae28fe40a5285 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 10 Jun 2019 12:45:27 +0300 Subject: [PATCH 26/50] IGNITE-11584 Code cleanup (javadoc). --- .../cache/persistence/freelist/AbstractFreeList.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index f81a92a9a8b3de..1eeda23b50b0fc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -546,7 +546,16 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken } } - /** {@inheritDoc} */ + /** + * Reduces the workload on the free list by writing multiple rows into a single memory page at once.
+ *
+ * Rows are sequentially added to the page as long as there is enough free space on it. If the row is large then + * those fragments that occupy the whole memory page are written to other pages, and the remainder is added to the + * current one. + * + * @param rows Rows. + * @throws IgniteCheckedException If failed. + */ @Override public void insertDataRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { try { From eeed6f07a15342ee250fb79d1918fdcafbedac41 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 11 Jun 2019 13:00:45 +0300 Subject: [PATCH 27/50] IGNITE-11584 Code cleanup (minor). --- .../processors/cache/GridCacheUtils.java | 34 +++++++++++++++++ .../preloader/GridDhtPartitionDemander.java | 37 ++----------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java index cc5dd42ef6cc92..337dcfd65cd3ae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java @@ -54,6 +54,7 @@ import org.apache.ignite.cache.store.CacheStoreSessionListener; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataPageEvictionMode; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; @@ -65,6 +66,7 @@ import org.apache.ignite.internal.cluster.ClusterGroupEmptyCheckedException; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; +import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedLockCancelledException; import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheAdapter; @@ -72,6 +74,7 @@ import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal; import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxLog; +import org.apache.ignite.internal.processors.cache.persistence.DataRegion; import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; @@ -1998,6 +2001,37 @@ public static boolean isCacheTemplateName(String cacheName) { return cacheName.endsWith("*"); } + /** + * @param memPlc Data region. + * @param size Data size in bytes. + * @return {@code True} if a specified amount of data can be stored in the memory region without evictions. + */ + public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { + DataRegionConfiguration plc = memPlc.config(); + + if (plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) + return true; + + PageMemory pageMem = memPlc.pageMemory(); + + int sysPageSize = pageMem.systemPageSize(); + + // The number of pages is calculated taking into account memory fragmentation and possible concurrent updates. + int pagesRequired = (size / sysPageSize) * 2; + + long maxPages = plc.getMaxSize() / sysPageSize; + + // There are enough pages left. + if (pagesRequired < maxPages - pageMem.loadedPages()) + return true; + + // Empty pages pool size restricted. + if (pagesRequired > plc.getEmptyPagesPoolSize()) + return false; + + return pagesRequired < maxPages * (1.0d - plc.getEvictionThreshold()); + } + /** * */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 8644a364e397c9..413c7d319d4165 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -34,15 +34,12 @@ import org.apache.ignite.cache.CacheRebalanceMode; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.configuration.DataPageEvictionMode; -import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.DiscoveryEvent; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; -import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.affinity.AffinityAssignment; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection; @@ -55,6 +52,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo; import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; +import org.apache.ignite.internal.processors.cache.GridCacheUtils; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology; @@ -774,7 +772,8 @@ public void handleSupplyMessage( boolean last = supplyMsg.last().containsKey(p); - boolean batched = canStoreWithoutEvictions(supplyMsg.messageSize()); + // In-memory evictions can be configured in such a way that batch mode may lead to OOME. + boolean batched = GridCacheUtils.isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize()); if (part.state() == MOVING) { boolean reserved = part.reserve(); @@ -870,36 +869,6 @@ public void handleSupplyMessage( } } - /** - * @param size Data size. - * @return {@code True} if rebalanced cache group allows writing a specified amount of data without evictions. - */ - private boolean canStoreWithoutEvictions(int size) { - DataRegionConfiguration plc = grp.dataRegion().config(); - - if (plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) - return true; - - PageMemory pageMem = grp.dataRegion().pageMemory(); - - int sysPageSize = pageMem.systemPageSize(); - - // The number of pages is calculated taking into account memory fragmentation and possible concurrent updates. - int pagesRequired = (size / sysPageSize) * 2; - - long maxPages = plc.getMaxSize() / sysPageSize; - - // There are enough pages left. - if (pagesRequired < maxPages - pageMem.loadedPages()) - return true; - - // Empty pages pool size restricted. - if (pagesRequired > plc.getEmptyPagesPoolSize()) - return false; - - return pagesRequired < maxPages * (1.0d - plc.getEvictionThreshold()); - } - /** * @param from Node which sent entry. * @param p Partition id. From dcf2fb5c1c59cb564ffb9026c442e7bfe46e547b Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 11 Jun 2019 14:22:51 +0300 Subject: [PATCH 28/50] IGNITE-11584 Minor. --- .../preloader/GridDhtPartitionDemander.java | 193 +++++++++--------- .../MemoryLeakAfterRebalanceSelfTest.java | 44 ++-- .../database/CacheFreeListSelfTest.java | 124 ++++++++--- 3 files changed, 217 insertions(+), 144 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 413c7d319d4165..b923fafd1bdc61 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -772,9 +772,6 @@ public void handleSupplyMessage( boolean last = supplyMsg.last().containsKey(p); - // In-memory evictions can be configured in such a way that batch mode may lead to OOME. - boolean batched = GridCacheUtils.isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize()); - if (part.state() == MOVING) { boolean reserved = part.reserve(); @@ -788,8 +785,13 @@ public void handleSupplyMessage( if (grp.mvccEnabled()) mvccPreloadEntries(topVer, node, p, infos); - else + else { + // In-memory evictions can be configured in such a way that batch mode will lead to OOME. + boolean batched = GridCacheUtils.isEnoughSpaceForData(grp.dataRegion(), + supplyMsg.messageSize()); + preloadEntries(topVer, node, p, infos, batched); + } // If message was last for this partition, // then we take ownership. @@ -869,97 +871,6 @@ public void handleSupplyMessage( } } - /** - * @param from Node which sent entry. - * @param p Partition id. - * @param infos Preloaded entries. - * @param topVer Topology version. - * @param batchSize Batch size. - * @throws IgniteCheckedException If failed. - */ - private boolean preloadEntriesBatched( - AffinityTopologyVersion topVer, - ClusterNode from, - int p, - Iterator infos, - int batchSize - ) throws IgniteCheckedException { - Map> cctxs = new HashMap<>(); - - // Groupping by cache id, since we cannot place entries from different caches on the same page. - for (GridCacheEntryInfo e; infos.hasNext() && batchSize-- > 0; - e = infos.next(), cctxs.computeIfAbsent(e.cacheId(), v -> new ArrayList<>(8)).add(e)); - - for (Map.Entry> cctxEntry : cctxs.entrySet()) { - GridCacheContext cctx = - grp.sharedGroup() ? ctx.cacheContext(cctxEntry.getKey()) : grp.singleCacheContext(); - - if (cctx == null) - continue; - - if (cctx.isNear()) - cctx = cctx.dhtCache().context(); - - List cctxInfos = cctxEntry.getValue(); - - Iterator rowsItr = null; - - try { - GridDhtLocalPartition part = cctx.topology().localPartition(p); - - // Filter NULL values (it means that we should remove entry from cache). - Collection hasValues = F.view(cctxInfos, info -> info.value() != null); - - cctx.shared().database().ensureFreeSpace(cctx.dataRegion()); - - // Store all cache entries to data store before get locks. - rowsItr = cctx.offheap().storeAll(cctx, part, hasValues).iterator(); - - for (GridCacheEntryInfo info : cctxInfos) { - CacheDataRow row = info.value() == null ? null : rowsItr.next(); - - // Link created cache entry in BPlusTree. - if (!preloadEntry(from, p, info, topVer, cctx, row)) - return false; - - //TODO: IGNITE-11330: Update metrics for touched cache only. - for (GridCacheContext cctx0 : grp.caches()) { - if (cctx0.statisticsEnabled()) - cctx0.cache().metrics0().onRebalanceKeyReceived(); - } - } - } - catch (GridDhtInvalidPartitionException ignored) { - if (log.isDebugEnabled()) - log.debug("Partition became invalid during rebalancing (will ignore): " + p); - - return false; - } - finally { - // Remove all unprocessed rows on error. - while (rowsItr != null && rowsItr.hasNext()) - cleanupRow(cctx, rowsItr.next()); - } - } - - return true; - } - - /** - * Remove row from data store. - * - * @param cctx Cache context. - * @param row Row to remove. - * @throws IgniteCheckedException If failed. - */ - private void cleanupRow(GridCacheContext cctx, CacheDataRow row) throws IgniteCheckedException { - if (row != null) { - RowStore rowStore = cctx.offheap().dataStore(cctx.topology().localPartition(row.partition())).rowStore(); - - rowStore.removeRow(row.link(), grp.statisticsHolderData()); - } - } - /** * Adds mvcc entries with theirs history to partition p. * @@ -1113,6 +1024,96 @@ else if (cctx.isNear()) } } + /** + * @param from Node which sent entry. + * @param p Partition id. + * @param infos Preloaded entries. + * @param topVer Topology version. + * @param batchSize Batch size. + * @throws IgniteCheckedException If failed. + */ + private boolean preloadEntriesBatched( + AffinityTopologyVersion topVer, + ClusterNode from, + int p, + Iterator infos, + int batchSize + ) throws IgniteCheckedException { + Map> cctxs = new HashMap<>(); + + // Groupping by cache id, since we cannot place entries from different caches on the same page. + for (GridCacheEntryInfo e; infos.hasNext() && batchSize-- > 0; + e = infos.next(), cctxs.computeIfAbsent(e.cacheId(), v -> new ArrayList<>(8)).add(e)); + + for (Map.Entry> cctxEntry : cctxs.entrySet()) { + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(cctxEntry.getKey()) : grp.singleCacheContext(); + + if (cctx == null) + continue; + + if (cctx.isNear()) + cctx = cctx.dhtCache().context(); + + List cctxInfos = cctxEntry.getValue(); + + Iterator rowsIter = null; + + try { + GridDhtLocalPartition part = cctx.topology().localPartition(p); + + // Filter NULL values (it means that we should remove entry from cache). + Collection updates = F.view(cctxInfos, info -> info.value() != null); + + cctx.shared().database().ensureFreeSpace(cctx.dataRegion()); + + // Store all cache entries to data store before get locks. + rowsIter = cctx.offheap().storeAll(cctx, part, updates).iterator(); + + for (GridCacheEntryInfo info : cctxInfos) { + CacheDataRow row = info.value() == null ? null : rowsIter.next(); + + if (!preloadEntry(from, p, info, topVer, cctx, row)) + return false; + + //TODO: IGNITE-11330: Update metrics for touched cache only. + for (GridCacheContext cctx0 : grp.caches()) { + if (cctx0.statisticsEnabled()) + cctx0.cache().metrics0().onRebalanceKeyReceived(); + } + } + } + catch (GridDhtInvalidPartitionException ignored) { + if (log.isDebugEnabled()) + log.debug("Partition became invalid during rebalancing (will ignore): " + p); + + return false; + } + finally { + // Remove all unprocessed rows on error. + while (rowsIter != null && rowsIter.hasNext()) + cleanupRow(cctx, rowsIter.next()); + } + } + + return true; + } + + /** + * Remove row from data store. + * + * @param cctx Cache context. + * @param row Row to remove. + * @throws IgniteCheckedException If failed. + */ + private void cleanupRow(GridCacheContext cctx, CacheDataRow row) throws IgniteCheckedException { + if (row != null) { + RowStore rowStore = cctx.offheap().dataStore(cctx.topology().localPartition(row.partition())).rowStore(); + + rowStore.removeRow(row.link(), grp.statisticsHolderData()); + } + } + /** * Adds {@code entry} to partition {@code p}. * @@ -1131,7 +1132,7 @@ private boolean preloadEntry( GridCacheEntryInfo entry, AffinityTopologyVersion topVer, GridCacheContext cctx, - CacheDataRow row + @Nullable CacheDataRow row ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java index f22d14f7e3c123..6609f7a5c83304 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java @@ -25,7 +25,6 @@ import javax.cache.Cache; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteException; -import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; @@ -47,7 +46,6 @@ import org.apache.ignite.spi.IgniteSpiException; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.testframework.GridTestUtils; -import org.apache.ignite.testframework.junits.WithSystemProperty; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.After; import org.junit.Before; @@ -77,20 +75,25 @@ public static Iterable parameters() { @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + boolean isSupplierNode = getTestIgniteInstanceIndex(igniteInstanceName) == 0; + + cfg.setCommunicationSpi(new TestCommunicationSpi(isSupplierNode ? preloadStartLatch : null)); + cfg.setDataStorageConfiguration(new DataStorageConfiguration(). - setDefaultDataRegionConfiguration(new DataRegionConfiguration() + setDefaultDataRegionConfiguration( + new DataRegionConfiguration() + .setMaxSize(200 * 1024 * 1024) .setPersistenceEnabled(true))); - cfg.setRebalanceThreadPoolSize(4); + CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); - cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME) - .setAffinity(new RendezvousAffinityFunction(false, 16)) - .setCacheMode(CacheMode.REPLICATED) - .setAtomicityMode(cacheAtomicityMode)); + ccfg.setCacheMode(CacheMode.REPLICATED); + ccfg.setAtomicityMode(cacheAtomicityMode); + ccfg.setAffinity(new RendezvousAffinityFunction(false, 16)); - boolean supplier = getTestIgniteInstanceIndex(igniteInstanceName) == 0; + cfg.setCacheConfiguration(ccfg); - cfg.setCommunicationSpi(new TestCommunicationSpi(supplier ? preloadStartLatch : null)); + cfg.setRebalanceThreadPoolSize(4); return cfg; } @@ -113,7 +116,6 @@ public void after() throws Exception { * @throws Exception If failed. */ @Test - @WithSystemProperty(key = IgniteSystemProperties.IGNITE_BASELINE_AUTO_ADJUST_ENABLED, value = "false") public void testPreloadingWithConcurrentUpdates() throws Exception { int size = GridTestUtils.SF.applyLB(500_000, 5_000); @@ -128,14 +130,14 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { node.cluster().active(true); + node.cluster().baselineAutoAdjustTimeout(0); + // Load data. node.cache(DEFAULT_CACHE_NAME).putAll(data); // Start 2 node. IgniteEx node2 = startGrid(1); - node.cluster().setBaselineTopology(node.cluster().nodes()); - IgniteInternalCache cache = node2.cachex(DEFAULT_CACHE_NAME); // Simulate concurrent updates when preloading. @@ -162,7 +164,7 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { GridCacheContext cctx = cache.context(); // Ensure that there are no duplicate entries left on data pages in page memory. - try (GridCloseableIterator> itr = cctx.offheap().cacheEntriesIterator( + try (GridCloseableIterator> iter = cctx.offheap().cacheEntriesIterator( cctx, true, true, @@ -171,8 +173,8 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { null, true)) { - while (itr.hasNext()) { - Cache.Entry entry = itr.next(); + while (iter.hasNext()) { + Cache.Entry entry = iter.next(); Integer key = entry.getKey(); @@ -188,11 +190,11 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { /** */ private static class TestCommunicationSpi extends TcpCommunicationSpi { /** */ - private final CountDownLatch latch; + private final CountDownLatch delaySupplyMessagesLatch; /** */ - private TestCommunicationSpi(CountDownLatch latch) { - this.latch = latch; + private TestCommunicationSpi(CountDownLatch delaySupplyMessagesLatch) { + this.delaySupplyMessagesLatch = delaySupplyMessagesLatch; } /** {@inheritDoc} */ @@ -205,8 +207,8 @@ private TestCommunicationSpi(CountDownLatch latch) { boolean supplyMsg = msg instanceof GridIoMessage && ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage; - if (supplyMsg && latch != null) - U.await(latch, 10, TimeUnit.SECONDS); + if (supplyMsg && delaySupplyMessagesLatch != null) + U.await(delaySupplyMessagesLatch, 10, TimeUnit.SECONDS); super.sendMessage(node, msg, ackC); } catch (IgniteInterruptedCheckedException e) { diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java index 9970d59430365b..7460b8a3fa15ed 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java @@ -87,80 +87,80 @@ public class CacheFreeListSelfTest extends GridCommonAbstractTest { * @throws Exception if failed. */ @Test - public void testInsertDeleteSingleThreaded_1024() throws Exception { - checkInsertDeleteSingleThreaded(1024); + public void testInsertDeleteSingleThreaded_batched_1024() throws Exception { + checkInsertDeleteSingleThreaded(1024, true); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteSingleThreaded_2048() throws Exception { - checkInsertDeleteSingleThreaded(2048); + public void testInsertDeleteSingleThreaded_batched_2048() throws Exception { + checkInsertDeleteSingleThreaded(2048, true); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteSingleThreaded_4096() throws Exception { - checkInsertDeleteSingleThreaded(4096); + public void testInsertDeleteSingleThreaded_batched_4096() throws Exception { + checkInsertDeleteSingleThreaded(4096, true); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteSingleThreaded_8192() throws Exception { - checkInsertDeleteSingleThreaded(8192); + public void testInsertDeleteSingleThreaded_batched_8192() throws Exception { + checkInsertDeleteSingleThreaded(8192, true); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteSingleThreaded_16384() throws Exception { - checkInsertDeleteSingleThreaded(16384); + public void testInsertDeleteSingleThreaded_batched_16384() throws Exception { + checkInsertDeleteSingleThreaded(16384, true); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteMultiThreaded_batched_1024() throws Exception { - checkInsertDeleteMultiThreaded(1024, true); + public void testInsertDeleteSingleThreaded_1024() throws Exception { + checkInsertDeleteSingleThreaded(1024); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteMultiThreaded_batched_2048() throws Exception { - checkInsertDeleteMultiThreaded(2048, true); + public void testInsertDeleteSingleThreaded_2048() throws Exception { + checkInsertDeleteSingleThreaded(2048); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteMultiThreaded_batched_4096() throws Exception { - checkInsertDeleteMultiThreaded(4096, true); + public void testInsertDeleteSingleThreaded_4096() throws Exception { + checkInsertDeleteSingleThreaded(4096); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteMultiThreaded_batched_8192() throws Exception { - checkInsertDeleteMultiThreaded(8192, true); + public void testInsertDeleteSingleThreaded_8192() throws Exception { + checkInsertDeleteSingleThreaded(8192); } /** * @throws Exception if failed. */ @Test - public void testInsertDeleteMultiThreaded_batched_16384() throws Exception { - checkInsertDeleteMultiThreaded(16384, true); + public void testInsertDeleteSingleThreaded_16384() throws Exception { + checkInsertDeleteSingleThreaded(16384); } /** @@ -203,11 +203,51 @@ public void testInsertDeleteMultiThreaded_16384() throws Exception { checkInsertDeleteMultiThreaded(16384); } + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_1024() throws Exception { + checkInsertDeleteMultiThreaded(1024, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_2048() throws Exception { + checkInsertDeleteMultiThreaded(2048, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_4096() throws Exception { + checkInsertDeleteMultiThreaded(4096, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_8192() throws Exception { + checkInsertDeleteMultiThreaded(8192, true); + } + + /** + * @throws Exception if failed. + */ + @Test + public void testInsertDeleteMultiThreaded_batched_16384() throws Exception { + checkInsertDeleteMultiThreaded(16384, true); + } + /** * @param pageSize Page size. * @throws Exception If failed. */ - protected void checkInsertDeleteMultiThreaded(final int pageSize) throws Exception { + protected void checkInsertDeleteMultiThreaded(int pageSize) throws Exception { checkInsertDeleteMultiThreaded(pageSize, false); } @@ -216,7 +256,7 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize) throws Excepti * @param batched Batch mode flag. * @throws Exception If failed. */ - protected void checkInsertDeleteMultiThreaded(final int pageSize, boolean batched) throws Exception { + protected void checkInsertDeleteMultiThreaded(final int pageSize, final boolean batched) throws Exception { final FreeList list = createFreeList(pageSize); Random rnd = new Random(); @@ -325,9 +365,19 @@ protected void checkInsertDeleteMultiThreaded(final int pageSize, boolean batche } /** - * @throws Exception if failed. + * @param pageSize Page size. + * @throws Exception If failed. */ protected void checkInsertDeleteSingleThreaded(int pageSize) throws Exception { + checkInsertDeleteSingleThreaded(pageSize, false); + } + + /** + * @param pageSize Page size. + * @param batched Batch mode flag. + * @throws Exception if failed. + */ + protected void checkInsertDeleteSingleThreaded(int pageSize, boolean batched) throws Exception { FreeList list = createFreeList(pageSize); Random rnd = new Random(); @@ -351,6 +401,8 @@ protected void checkInsertDeleteSingleThreaded(int pageSize) throws Exception { boolean grow = true; + List rows = new ArrayList<>(BATCH_SIZE); + for (int i = 0; i < 1_000_000; i++) { if (grow) { if (stored.size() > 20_000) { @@ -375,13 +427,31 @@ protected void checkInsertDeleteSingleThreaded(int pageSize) throws Exception { TestDataRow row = new TestDataRow(keySize, valSize); - list.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); + if (batched) + rows.add(row); + else { + list.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); - assertTrue(row.link() != 0L); + assertTrue(row.link() != 0L); + + TestDataRow old = stored.put(row.link(), row); + + assertNull(old); + } - TestDataRow old = stored.put(row.link(), row); + if (rows.size() == BATCH_SIZE) { + list.insertDataRows(rows, IoStatisticsHolderNoOp.INSTANCE); - assertNull(old); + for (TestDataRow row0 : rows) { + assertTrue(row0.link() != 0L); + + TestDataRow old = stored.put(row0.link(), row0); + + assertNull(old); + } + + rows.clear(); + } } else { Iterator it = stored.values().iterator(); From 7511ca54a2e20cbcf642a77862b69ce9880f6ae2 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Thu, 13 Jun 2019 16:09:59 +0300 Subject: [PATCH 29/50] IGNITE-11584 Removed redundant groupping by cacheid. --- .../cache/IgniteCacheOffheapManager.java | 8 +- .../cache/IgniteCacheOffheapManagerImpl.java | 27 +++--- .../preloader/GridDhtPartitionDemander.java | 89 +++++++++---------- .../persistence/GridCacheOffheapManager.java | 8 +- 4 files changed, 63 insertions(+), 69 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 507bbc96c46cd4..e65fbe9c8aa4fe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -192,15 +192,13 @@ public void invoke(GridCacheContext cctx, KeyCacheObject key, GridDhtLocalPartit throws IgniteCheckedException; /** - * @param cctx Cache context. * @param part Partition. * @param entries Entries. * @throws IgniteCheckedException If failed. */ public List storeAll( - GridCacheContext cctx, GridDhtLocalPartition part, - Collection entries + Collection entries ) throws IgniteCheckedException; /** @@ -744,14 +742,12 @@ void update( /** - * @param cctx Cache context. * @param entries Entries. * @return Created rows. * @throws IgniteCheckedException If failed. */ public List storeAll( - GridCacheContext cctx, - Collection entries + Collection entries ) throws IgniteCheckedException; /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index b15e71ce8fd49f..1ddf57fc341f83 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -449,11 +449,10 @@ private Iterator cacheData(boolean primary, boolean backup, Affi /** {@inheritDoc} */ @Override public List storeAll( - GridCacheContext cctx, GridDhtLocalPartition part, - Collection entries + Collection entries ) throws IgniteCheckedException { - return dataStore(part).storeAll(cctx, entries); + return dataStore(part).storeAll(entries); } /** {@inheritDoc} */ @@ -1705,8 +1704,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo /** {@inheritDoc} */ @Override public List storeAll( - GridCacheContext cctx, - Collection infos + Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) throw new NodeStoppingException("Operation has been cancelled (node is stopping)."); @@ -1714,15 +1712,12 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo List rows = new ArrayList<>(infos.size()); try { - assert cctx.shared().database().checkpointLockIsHeldByThread(); - - assert !cctx.mvccEnabled(); - - int cacheId = cctx.group().storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; - IoStatisticsHolder statHolder = grp.statisticsHolderData(); for (GridCacheEntryInfo info : infos) { + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); + KeyCacheObject key = info.key(); CacheObject val = info.value(); @@ -1731,6 +1726,8 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo key.valueBytes(coCtx); val.valueBytes(coCtx); + int cacheId = grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID; + DataRow row = makeDataRow(key, val, info.version(), info.expireTime(), cacheId); rows.add(row); @@ -1738,15 +1735,19 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo rowStore().addRows(rows, statHolder); - if (grp.sharedGroup() && !cctx.group().storeCacheIdInDataPage()) { + Iterator iter = infos.iterator(); + + if (grp.sharedGroup() && !grp.storeCacheIdInDataPage()) { for (CacheDataRow row : rows) - ((DataRow)row).cacheId(cctx.cacheId()); + ((DataRow)row).cacheId(iter.next().cacheId()); } } finally { busyLock.leaveBusy(); } + assert rows.size() == infos.size(); + return rows; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index b923fafd1bdc61..8caba68c8504c1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1027,7 +1027,7 @@ else if (cctx.isNear()) /** * @param from Node which sent entry. * @param p Partition id. - * @param infos Preloaded entries. + * @param infosIter Preloaded entries. * @param topVer Topology version. * @param batchSize Batch size. * @throws IgniteCheckedException If failed. @@ -1036,64 +1036,62 @@ private boolean preloadEntriesBatched( AffinityTopologyVersion topVer, ClusterNode from, int p, - Iterator infos, + Iterator infosIter, int batchSize ) throws IgniteCheckedException { - Map> cctxs = new HashMap<>(); + List infos = new ArrayList<>(batchSize); - // Groupping by cache id, since we cannot place entries from different caches on the same page. - for (GridCacheEntryInfo e; infos.hasNext() && batchSize-- > 0; - e = infos.next(), cctxs.computeIfAbsent(e.cacheId(), v -> new ArrayList<>(8)).add(e)); + while (infosIter.hasNext() && infos.size() < batchSize) { + GridCacheEntryInfo info = infosIter.next(); - for (Map.Entry> cctxEntry : cctxs.entrySet()) { - GridCacheContext cctx = - grp.sharedGroup() ? ctx.cacheContext(cctxEntry.getKey()) : grp.singleCacheContext(); + GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - if (cctx == null) - continue; + if (cctx != null) + infos.add(info); + } - if (cctx.isNear()) - cctx = cctx.dhtCache().context(); + Iterator rowsIter = null; - List cctxInfos = cctxEntry.getValue(); + try { + GridDhtLocalPartition part = grp.topology().localPartition(p); - Iterator rowsIter = null; + // Filter NULL values (this means we need to remove the cache entry). + Collection updates = F.view(infos, info -> info.value() != null); - try { - GridDhtLocalPartition part = cctx.topology().localPartition(p); + grp.shared().database().ensureFreeSpace(grp.dataRegion()); - // Filter NULL values (it means that we should remove entry from cache). - Collection updates = F.view(cctxInfos, info -> info.value() != null); + // Create data rows on data pages before getting locks on cache entries. + rowsIter = grp.offheap().storeAll(part, updates).iterator(); - cctx.shared().database().ensureFreeSpace(cctx.dataRegion()); + for (GridCacheEntryInfo info : infos) { + CacheDataRow row = info.value() == null ? null : rowsIter.next(); - // Store all cache entries to data store before get locks. - rowsIter = cctx.offheap().storeAll(cctx, part, updates).iterator(); + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - for (GridCacheEntryInfo info : cctxInfos) { - CacheDataRow row = info.value() == null ? null : rowsIter.next(); + if (cctx.isNear()) + cctx = cctx.dhtCache().context(); - if (!preloadEntry(from, p, info, topVer, cctx, row)) - return false; + if (!preloadEntry(from, p, info, topVer, cctx, row)) + return false; - //TODO: IGNITE-11330: Update metrics for touched cache only. - for (GridCacheContext cctx0 : grp.caches()) { - if (cctx0.statisticsEnabled()) - cctx0.cache().metrics0().onRebalanceKeyReceived(); - } + //TODO: IGNITE-11330: Update metrics for touched cache only. + for (GridCacheContext cctx0 : grp.caches()) { + if (cctx0.statisticsEnabled()) + cctx0.cache().metrics0().onRebalanceKeyReceived(); } } - catch (GridDhtInvalidPartitionException ignored) { - if (log.isDebugEnabled()) - log.debug("Partition became invalid during rebalancing (will ignore): " + p); + } + catch (GridDhtInvalidPartitionException ignored) { + if (log.isDebugEnabled()) + log.debug("Partition became invalid during rebalancing (will ignore): " + p); - return false; - } - finally { - // Remove all unprocessed rows on error. - while (rowsIter != null && rowsIter.hasNext()) - cleanupRow(cctx, rowsIter.next()); - } + return false; + } + finally { + // Remove all unprocessed rows on error. + while (rowsIter != null && rowsIter.hasNext()) + cleanupRow(rowsIter.next()); } return true; @@ -1102,13 +1100,12 @@ private boolean preloadEntriesBatched( /** * Remove row from data store. * - * @param cctx Cache context. * @param row Row to remove. * @throws IgniteCheckedException If failed. */ - private void cleanupRow(GridCacheContext cctx, CacheDataRow row) throws IgniteCheckedException { + private void cleanupRow(CacheDataRow row) throws IgniteCheckedException { if (row != null) { - RowStore rowStore = cctx.offheap().dataStore(cctx.topology().localPartition(row.partition())).rowStore(); + RowStore rowStore = grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(); rowStore.removeRow(row.link(), grp.statisticsHolderData()); } @@ -1173,7 +1170,7 @@ private boolean preloadEntry( else { cached.touch(); // Start tracking. - cleanupRow(cctx, row); // Remove pre-created row. + cleanupRow(row); // Remove pre-created row. if (log.isTraceEnabled()) log.trace("Rebalancing entry is already in cache (will ignore) [key=" + cached.key() + @@ -1186,7 +1183,7 @@ private boolean preloadEntry( log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" + cached.key() + ", part=" + p + ']'); - cleanupRow(cctx, row); + cleanupRow(row); } catch (GridDhtInvalidPartitionException ignored) { if (log.isDebugEnabled()) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 75ea0ed8d726e1..71902a3710e3a2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2401,16 +2401,16 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { delegate.invoke(cctx, key, c); } - /** {@inheritDoc} */ + /** {@inheritDoc} + * @param entries*/ @Override public List storeAll( - GridCacheContext cctx, - Collection entries + Collection entries ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); CacheDataStore delegate = init0(false); - return delegate.storeAll(cctx, entries); + return delegate.storeAll(entries); } /** {@inheritDoc} */ From eff78716aa842b0a7264a490a160f956df3142b3 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 14 Jun 2019 17:24:41 +0300 Subject: [PATCH 30/50] IGNITE-11584 Minor (javadocs). --- .../ignite/internal/processors/cache/GridCacheUtils.java | 9 ++++++--- .../processors/cache/IgniteCacheOffheapManager.java | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java index 337dcfd65cd3ae..1fd634ba7ababd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java @@ -2002,6 +2002,9 @@ public static boolean isCacheTemplateName(String cacheName) { } /** + * Calculates whether there is enough free space in a region to store a specified amount of data. Required number of + * pages for data is estimated taking into account memory fragmentation and possible concurrent updates. + * * @param memPlc Data region. * @param size Data size in bytes. * @return {@code True} if a specified amount of data can be stored in the memory region without evictions. @@ -2009,7 +2012,7 @@ public static boolean isCacheTemplateName(String cacheName) { public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { DataRegionConfiguration plc = memPlc.config(); - if (plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) + if (size <= 0 || plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) return true; PageMemory pageMem = memPlc.pageMemory(); @@ -2017,7 +2020,7 @@ public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { int sysPageSize = pageMem.systemPageSize(); // The number of pages is calculated taking into account memory fragmentation and possible concurrent updates. - int pagesRequired = (size / sysPageSize) * 2; + int pagesRequired = Math.round((size / (float)sysPageSize) * 2); long maxPages = plc.getMaxSize() / sysPageSize; @@ -2029,7 +2032,7 @@ public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { if (pagesRequired > plc.getEmptyPagesPoolSize()) return false; - return pagesRequired < maxPages * (1.0d - plc.getEvictionThreshold()); + return pagesRequired < Math.round(maxPages * (1.0d - plc.getEvictionThreshold())); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index e65fbe9c8aa4fe..b7f3d446d34446 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -192,6 +192,8 @@ public void invoke(GridCacheContext cctx, KeyCacheObject key, GridDhtLocalPartit throws IgniteCheckedException; /** + * Put entries into the data store. + * * @param part Partition. * @param entries Entries. * @throws IgniteCheckedException If failed. @@ -742,6 +744,8 @@ void update( /** + * Put entries into the data store. + * * @param entries Entries. * @return Created rows. * @throws IgniteCheckedException If failed. From b266bba3d1ae9d39b4b39ef38f4c56d1319da063 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 14 Jun 2019 17:38:04 +0300 Subject: [PATCH 31/50] IGNITE-11584 Minor. --- .../processors/cache/IgniteCacheOffheapManager.java | 1 + .../dht/preloader/GridDhtPartitionDemander.java | 3 ++- .../cache/persistence/GridCacheOffheapManager.java | 3 +-- .../internal/processors/cache/persistence/RowStore.java | 1 + .../cache/persistence/freelist/AbstractFreeList.java | 9 ++++----- .../processors/cache/persistence/freelist/FreeList.java | 5 +++++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index b7f3d446d34446..054e0b4d871129 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -196,6 +196,7 @@ public void invoke(GridCacheContext cctx, KeyCacheObject key, GridDhtLocalPartit * * @param part Partition. * @param entries Entries. + * @return Created rows. * @throws IgniteCheckedException If failed. */ public List storeAll( diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 8caba68c8504c1..3046363944f946 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1025,11 +1025,12 @@ else if (cctx.isNear()) } /** + * @param topVer Topology version. * @param from Node which sent entry. * @param p Partition id. * @param infosIter Preloaded entries. - * @param topVer Topology version. * @param batchSize Batch size. + * @return {@code False} if partition has become invalid during preloading. * @throws IgniteCheckedException If failed. */ private boolean preloadEntriesBatched( diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 71902a3710e3a2..651b8101f2d105 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2401,8 +2401,7 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { delegate.invoke(cctx, key, c); } - /** {@inheritDoc} - * @param entries*/ + /** {@inheritDoc} */ @Override public List storeAll( Collection entries ) throws IgniteCheckedException { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java index 3edc917dd23bf1..85bcd6ddf45a9f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java @@ -120,6 +120,7 @@ public void addRow(CacheDataRow row, IoStatisticsHolder statHolder) throws Ignit /** * @param rows Rows. + * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ public void addRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 1eeda23b50b0fc..d6677de2961da2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -138,9 +138,7 @@ private final class UpdateRowHandler extends PageHandler { /** Write handler which doesn't put memory page into the free list after an update. */ private final PageHandler writeRowKeepPage = new WriteRowHandler(false); - /** - * - */ + /** */ private final class WriteRowHandler extends PageHandler { /** */ private final boolean putPageIntoFreeList; @@ -554,6 +552,7 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken * current one. * * @param rows Rows. + * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ @Override public void insertDataRows(Collection rows, @@ -614,11 +613,11 @@ else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) // Page is taken assert pageAddr != 0; - AbstractDataPageIO io = initIo == null ? PageIO.getPageIO(pageAddr) : initIo; - boolean dirty = false; try { + AbstractDataPageIO io = initIo == null ? PageIO.getPageIO(pageAddr) : initIo; + // Fill the page up to the end. while (iter.hasNext() || written != COMPLETE) { if (written == COMPLETE) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java index 894c1aa64faca0..cefde1cd346fae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/FreeList.java @@ -29,12 +29,14 @@ public interface FreeList { /** * @param row Row. + * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException; /** * @param rows Rows. + * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ public void insertDataRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException; @@ -42,6 +44,7 @@ public interface FreeList { /** * @param link Row link. * @param row New row data. + * @param statHolder Statistics holder to track IO operations. * @return {@code True} if was able to update row. * @throws IgniteCheckedException If failed. */ @@ -53,6 +56,7 @@ public interface FreeList { * @param arg Handler argument. * @param Argument type. * @param Result type. + * @param statHolder Statistics holder to track IO operations. * @return Result. * @throws IgniteCheckedException If failed. */ @@ -61,6 +65,7 @@ public R updateDataRow(long link, PageHandler pageHnd, S arg, IoSta /** * @param link Row link. + * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ public void removeDataRowByLink(long link, IoStatisticsHolder statHolder) throws IgniteCheckedException; From 8f3ab0e95ba18d3e8d3f70408e9cfa95b2fb4afa Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 18 Jun 2019 10:58:55 +0300 Subject: [PATCH 32/50] IGNITE-11584 Minor. --- .../ignite/internal/processors/cache/GridCacheUtils.java | 6 ++---- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java index 1fd634ba7ababd..7f8d00f29ad0d9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java @@ -2002,8 +2002,7 @@ public static boolean isCacheTemplateName(String cacheName) { } /** - * Calculates whether there is enough free space in a region to store a specified amount of data. Required number of - * pages for data is estimated taking into account memory fragmentation and possible concurrent updates. + * Calculates whether there is enough free space in a region to store a specified amount of data. * * @param memPlc Data region. * @param size Data size in bytes. @@ -2019,8 +2018,7 @@ public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { int sysPageSize = pageMem.systemPageSize(); - // The number of pages is calculated taking into account memory fragmentation and possible concurrent updates. - int pagesRequired = Math.round((size / (float)sysPageSize) * 2); + int pagesRequired = Math.round(size / (float)sysPageSize); long maxPages = plc.getMaxSize() / sysPageSize; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 3046363944f946..33b5de83c7f8cd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -788,7 +788,7 @@ public void handleSupplyMessage( else { // In-memory evictions can be configured in such a way that batch mode will lead to OOME. boolean batched = GridCacheUtils.isEnoughSpaceForData(grp.dataRegion(), - supplyMsg.messageSize()); + supplyMsg.messageSize() * 2); preloadEntries(topVer, node, p, infos, batched); } From d3023e1d92e8c31b64bec67cdd463d2c9610c552 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 18 Jun 2019 11:00:14 +0300 Subject: [PATCH 33/50] IGNITE-11584 Minor. --- .../ignite/internal/processors/cache/GridCacheUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java index 7f8d00f29ad0d9..83421f31211f7f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java @@ -2008,7 +2008,7 @@ public static boolean isCacheTemplateName(String cacheName) { * @param size Data size in bytes. * @return {@code True} if a specified amount of data can be stored in the memory region without evictions. */ - public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { + public static boolean isEnoughSpaceForData(DataRegion memPlc, long size) { DataRegionConfiguration plc = memPlc.config(); if (size <= 0 || plc.isPersistenceEnabled() || plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED) @@ -2018,7 +2018,7 @@ public static boolean isEnoughSpaceForData(DataRegion memPlc, int size) { int sysPageSize = pageMem.systemPageSize(); - int pagesRequired = Math.round(size / (float)sysPageSize); + long pagesRequired = Math.round(size / (double)sysPageSize); long maxPages = plc.getMaxSize() / sysPageSize; From 19c0213fb7c1d7295c0820d27fdeff54164aaf31 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 19 Jun 2019 00:32:46 +0300 Subject: [PATCH 34/50] IGNITE-11584 Test code cleanup. --- .../MemoryLeakAfterRebalanceSelfTest.java | 84 ++++++------------- 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java index 6609f7a5c83304..19809d674d46ea 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/MemoryLeakAfterRebalanceSelfTest.java @@ -20,31 +20,24 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import javax.cache.Cache; import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; -import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; -import org.apache.ignite.internal.IgniteInterruptedCheckedException; -import org.apache.ignite.internal.managers.communication.GridIoMessage; +import org.apache.ignite.internal.TestRecordingCommunicationSpi; import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.GridCacheGroupIdMessage; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage; import org.apache.ignite.internal.util.lang.GridCloseableIterator; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.lang.IgniteInClosure; -import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.spi.IgniteSpiException; -import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.After; @@ -58,9 +51,6 @@ */ @RunWith(Parameterized.class) public class MemoryLeakAfterRebalanceSelfTest extends GridCommonAbstractTest { - /** */ - private final CountDownLatch preloadStartLatch = new CountDownLatch(1); - /** */ @Parameterized.Parameter public CacheAtomicityMode cacheAtomicityMode; @@ -75,9 +65,7 @@ public static Iterable parameters() { @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - boolean isSupplierNode = getTestIgniteInstanceIndex(igniteInstanceName) == 0; - - cfg.setCommunicationSpi(new TestCommunicationSpi(isSupplierNode ? preloadStartLatch : null)); + cfg.setCommunicationSpi(new TestRecordingCommunicationSpi()); cfg.setDataStorageConfiguration(new DataStorageConfiguration(). setDefaultDataRegionConfiguration( @@ -126,30 +114,38 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { data.put(i, i + " v.1"); // Start 1 node. - Ignite node = startGrid(0); + Ignite node0 = startGrid(0); + + node0.cluster().active(true); - node.cluster().active(true); + node0.cluster().baselineAutoAdjustTimeout(0); - node.cluster().baselineAutoAdjustTimeout(0); + IgniteCache cache0 = node0.cache(DEFAULT_CACHE_NAME); // Load data. - node.cache(DEFAULT_CACHE_NAME).putAll(data); + cache0.putAll(data); + + TestRecordingCommunicationSpi.spi(node0) + .blockMessages((node, msg) -> + msg instanceof GridDhtPartitionSupplyMessage + && ((GridCacheGroupIdMessage)msg).groupId() == groupIdForCache(node0, DEFAULT_CACHE_NAME) + ); // Start 2 node. - IgniteEx node2 = startGrid(1); + IgniteEx node1 = startGrid(1); - IgniteInternalCache cache = node2.cachex(DEFAULT_CACHE_NAME); + TestRecordingCommunicationSpi.spi(node0).waitForBlocked(); // Simulate concurrent updates when preloading. for (int i = 0; i < size; i += 10) { String val = i + " v.2"; - cache.put(i, val); + cache0.put(i, val); data.put(i, val); // Start preloading. - if (i > size / 2) - preloadStartLatch.countDown(); + if (i == size / 2) + TestRecordingCommunicationSpi.spi(node0).stopBlock(); } awaitPartitionMapExchange(); @@ -159,11 +155,13 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { awaitPartitionMapExchange(); - assertEquals(data.size(), cache.size()); + IgniteInternalCache cache1 = node1.cachex(DEFAULT_CACHE_NAME); + + assertEquals(data.size(), cache1.size()); - GridCacheContext cctx = cache.context(); + GridCacheContext cctx = cache1.context(); - // Ensure that there are no duplicate entries left on data pages in page memory. + // Make sure that there are no duplicate entries on the data pages in the pages memory. try (GridCloseableIterator> iter = cctx.offheap().cacheEntriesIterator( cctx, true, @@ -186,34 +184,4 @@ public void testPreloadingWithConcurrentUpdates() throws Exception { assertTrue(data.isEmpty()); } - - /** */ - private static class TestCommunicationSpi extends TcpCommunicationSpi { - /** */ - private final CountDownLatch delaySupplyMessagesLatch; - - /** */ - private TestCommunicationSpi(CountDownLatch delaySupplyMessagesLatch) { - this.delaySupplyMessagesLatch = delaySupplyMessagesLatch; - } - - /** {@inheritDoc} */ - @Override public void sendMessage( - final ClusterNode node, - final Message msg, - final IgniteInClosure ackC - ) throws IgniteSpiException { - try { - boolean supplyMsg = msg instanceof GridIoMessage && - ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage; - - if (supplyMsg && delaySupplyMessagesLatch != null) - U.await(delaySupplyMessagesLatch, 10, TimeUnit.SECONDS); - - super.sendMessage(node, msg, ackC); - } catch (IgniteInterruptedCheckedException e) { - throw new IgniteSpiException(e); - } - } - } } From 4e57babfa0fd06502e5ed8f30a8f721bd7e88c59 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Fri, 21 Jun 2019 17:45:15 +0300 Subject: [PATCH 35/50] IGNITE-11584 Code cleanup. --- .../cache/IgniteCacheOffheapManager.java | 4 +- .../cache/IgniteCacheOffheapManagerImpl.java | 4 +- .../preloader/GridDhtPartitionDemander.java | 130 ++++++++---------- .../persistence/GridCacheOffheapManager.java | 2 +- 4 files changed, 59 insertions(+), 81 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 054e0b4d871129..84b4d08b22a69b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -199,7 +199,7 @@ public void invoke(GridCacheContext cctx, KeyCacheObject key, GridDhtLocalPartit * @return Created rows. * @throws IgniteCheckedException If failed. */ - public List storeAll( + public Collection storeAll( GridDhtLocalPartition part, Collection entries ) throws IgniteCheckedException; @@ -751,7 +751,7 @@ void update( * @return Created rows. * @throws IgniteCheckedException If failed. */ - public List storeAll( + public Collection storeAll( Collection entries ) throws IgniteCheckedException; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 1ddf57fc341f83..a36337547fc3b3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -448,7 +448,7 @@ private Iterator cacheData(boolean primary, boolean backup, Affi } /** {@inheritDoc} */ - @Override public List storeAll( + @Override public Collection storeAll( GridDhtLocalPartition part, Collection entries ) throws IgniteCheckedException { @@ -1703,7 +1703,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } /** {@inheritDoc} */ - @Override public List storeAll( + @Override public Collection storeAll( Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 33b5de83c7f8cd..7d843d64c0c7a9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -52,7 +52,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo; import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.cache.GridCacheUtils; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology; @@ -84,6 +83,7 @@ import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_PART_LOADED; import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_STARTED; import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_STOPPED; +import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isEnoughSpaceForData; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.MOVING; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_PRELOAD; @@ -785,13 +785,10 @@ public void handleSupplyMessage( if (grp.mvccEnabled()) mvccPreloadEntries(topVer, node, p, infos); - else { - // In-memory evictions can be configured in such a way that batch mode will lead to OOME. - boolean batched = GridCacheUtils.isEnoughSpaceForData(grp.dataRegion(), - supplyMsg.messageSize() * 2); - - preloadEntries(topVer, node, p, infos, batched); - } + else if (isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize() * 2)) + preloadEntriesBatched(topVer, node, p, infos); + else + preloadEntries(topVer, node, p, infos); // If message was last for this partition, // then we take ownership. @@ -964,11 +961,10 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node * @param p Partition id. * @param infos Entries info for preload. * @param topVer Topology version. - * @param batched Preload entries in batch mode. * @throws IgniteInterruptedCheckedException If interrupted. */ private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p, - Iterator infos, boolean batched) throws IgniteCheckedException { + Iterator infos) throws IgniteCheckedException { GridCacheContext cctx = null; // Loop through all received entries and try to preload them. @@ -976,18 +972,6 @@ private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, in ctx.database().checkpointReadLock(); try { - if (batched) { - if (!preloadEntriesBatched(topVer, node, p, infos, CHECKPOINT_THRESHOLD)) { - if (log.isTraceEnabled()) - log.trace("Got entries for invalid partition during " + - "preloading (will skip) [p=" + p + ']'); - - return; - } - - continue; - } - for (int i = 0; i < CHECKPOINT_THRESHOLD; i++) { if (!infos.hasNext()) break; @@ -1028,74 +1012,69 @@ else if (cctx.isNear()) * @param topVer Topology version. * @param from Node which sent entry. * @param p Partition id. - * @param infosIter Preloaded entries. - * @param batchSize Batch size. - * @return {@code False} if partition has become invalid during preloading. + * @param infos Preloaded entries. * @throws IgniteCheckedException If failed. */ - private boolean preloadEntriesBatched( + private void preloadEntriesBatched( AffinityTopologyVersion topVer, ClusterNode from, int p, - Iterator infosIter, - int batchSize + Iterator infos ) throws IgniteCheckedException { - List infos = new ArrayList<>(batchSize); + while (infos.hasNext()) { + List batch = new ArrayList<>(CHECKPOINT_THRESHOLD); - while (infosIter.hasNext() && infos.size() < batchSize) { - GridCacheEntryInfo info = infosIter.next(); + while (infos.hasNext() && batch.size() < CHECKPOINT_THRESHOLD) { + GridCacheEntryInfo info = infos.next(); - GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); + GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - if (cctx != null) - infos.add(info); - } + if (cctx != null) + batch.add(info); + } - Iterator rowsIter = null; + Iterator rowsIter = null; - try { - GridDhtLocalPartition part = grp.topology().localPartition(p); + ctx.database().checkpointReadLock(); - // Filter NULL values (this means we need to remove the cache entry). - Collection updates = F.view(infos, info -> info.value() != null); + try { + GridDhtLocalPartition part = grp.topology().localPartition(p); - grp.shared().database().ensureFreeSpace(grp.dataRegion()); + // Filter NULL values (this means we need to remove the cache entry). + Collection updates = F.view(batch, info -> info.value() != null); - // Create data rows on data pages before getting locks on cache entries. - rowsIter = grp.offheap().storeAll(part, updates).iterator(); + grp.shared().database().ensureFreeSpace(grp.dataRegion()); - for (GridCacheEntryInfo info : infos) { - CacheDataRow row = info.value() == null ? null : rowsIter.next(); + // Create data rows on data pages before getting locks on cache entries. + rowsIter = grp.offheap().storeAll(part, updates).iterator(); - GridCacheContext cctx = - grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); + for (GridCacheEntryInfo info : batch) { + CacheDataRow row = info.value() == null ? null : rowsIter.next(); - if (cctx.isNear()) - cctx = cctx.dhtCache().context(); + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - if (!preloadEntry(from, p, info, topVer, cctx, row)) - return false; + if (cctx.isNear()) + cctx = cctx.dhtCache().context(); - //TODO: IGNITE-11330: Update metrics for touched cache only. - for (GridCacheContext cctx0 : grp.caches()) { - if (cctx0.statisticsEnabled()) - cctx0.cache().metrics0().onRebalanceKeyReceived(); + if (!preloadEntry(from, p, info, topVer, cctx, row)) + return; + + //TODO: IGNITE-11330: Update metrics for touched cache only. + for (GridCacheContext cctx0 : grp.caches()) { + if (cctx0.statisticsEnabled()) + cctx0.cache().metrics0().onRebalanceKeyReceived(); + } } } - } - catch (GridDhtInvalidPartitionException ignored) { - if (log.isDebugEnabled()) - log.debug("Partition became invalid during rebalancing (will ignore): " + p); + finally { + // Remove all unprocessed rows on error. + while (rowsIter != null && rowsIter.hasNext()) + cleanupRow(rowsIter.next()); - return false; - } - finally { - // Remove all unprocessed rows on error. - while (rowsIter != null && rowsIter.hasNext()) - cleanupRow(rowsIter.next()); + ctx.database().checkpointReadUnlock(); + } } - - return true; } /** @@ -1105,11 +1084,9 @@ private boolean preloadEntriesBatched( * @throws IgniteCheckedException If failed. */ private void cleanupRow(CacheDataRow row) throws IgniteCheckedException { - if (row != null) { - RowStore rowStore = grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(); + RowStore rowStore = grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(); - rowStore.removeRow(row.link(), grp.statisticsHolderData()); - } + rowStore.removeRow(row.link(), grp.statisticsHolderData()); } /** @@ -1134,6 +1111,8 @@ private boolean preloadEntry( ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); + boolean updated = false; + try { GridCacheEntryEx cached = null; @@ -1146,7 +1125,7 @@ private boolean preloadEntry( } if (preloadPred == null || preloadPred.apply(entry)) { - if (cached.initialValue( + if (updated = cached.initialValue( entry.value(), entry.version(), cctx.mvccEnabled() ? ((MvccVersionAware)entry).mvccVersion() : null, @@ -1171,8 +1150,6 @@ private boolean preloadEntry( else { cached.touch(); // Start tracking. - cleanupRow(row); // Remove pre-created row. - if (log.isTraceEnabled()) log.trace("Rebalancing entry is already in cache (will ignore) [key=" + cached.key() + ", part=" + p + ']'); @@ -1183,8 +1160,6 @@ private boolean preloadEntry( if (log.isTraceEnabled()) log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" + cached.key() + ", part=" + p + ']'); - - cleanupRow(row); } catch (GridDhtInvalidPartitionException ignored) { if (log.isDebugEnabled()) @@ -1199,6 +1174,9 @@ private boolean preloadEntry( catch (IgniteCheckedException e) { throw new IgniteCheckedException("Failed to cache rebalanced entry (will stop rebalancing) [local=" + ctx.localNode() + ", node=" + from.id() + ", key=" + entry.key() + ", part=" + p + ']', e); + } finally { + if (!updated && row != null) + cleanupRow(row); } return true; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 651b8101f2d105..87368b95f22878 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2402,7 +2402,7 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { } /** {@inheritDoc} */ - @Override public List storeAll( + @Override public Collection storeAll( Collection entries ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); From fe0624d94b778e835989e9cf560d631b67449175 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 24 Jun 2019 15:29:31 +0300 Subject: [PATCH 36/50] IGNITE-11584 Code cleanup. --- .../preloader/GridDhtPartitionDemander.java | 112 +++++++----------- 1 file changed, 44 insertions(+), 68 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 7d843d64c0c7a9..47f49fed55ee71 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -59,7 +59,6 @@ import org.apache.ignite.internal.processors.cache.mvcc.MvccVersionAware; import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxState; import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; -import org.apache.ignite.internal.processors.cache.persistence.RowStore; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; import org.apache.ignite.internal.util.future.GridCompoundFuture; @@ -783,21 +782,28 @@ public void handleSupplyMessage( try { Iterator infos = e.getValue().infos().iterator(); - if (grp.mvccEnabled()) - mvccPreloadEntries(topVer, node, p, infos); - else if (isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize() * 2)) - preloadEntriesBatched(topVer, node, p, infos); - else - preloadEntries(topVer, node, p, infos); - - // If message was last for this partition, - // then we take ownership. - if (last) { - fut.partitionDone(nodeId, p, true); - + try { + if (grp.mvccEnabled()) + mvccPreloadEntries(topVer, node, p, infos); + else if (isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize() * 2)) + preloadEntriesBatched(topVer, node, p, infos); + else + preloadEntries(topVer, node, p, infos); + } + catch (GridDhtInvalidPartitionException ignored) { if (log.isDebugEnabled()) - log.debug("Finished rebalancing partition: " + - "[" + demandRoutineInfo(topicId, nodeId, supplyMsg) + ", p=" + p + "]"); + log.debug("Partition became invalid during rebalancing (will ignore): " + p); + } + finally { + // If message was last for this partition, + // then we take ownership. + if (last) { + fut.partitionDone(nodeId, p, true); + + if (log.isDebugEnabled()) + log.debug("Finished rebalancing partition: " + + "[" + demandRoutineInfo(topicId, nodeId, supplyMsg) + ", p=" + p + "]"); + } } } finally { @@ -923,14 +929,7 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node } if (cctx != null) { - if (!mvccPreloadEntry(cctx, node, entryHist, topVer, p)) { - if (log.isTraceEnabled()) - log.trace("Got entries for invalid partition during " + - "preloading (will skip) [p=" + p + - ", entry=" + entryHist.get(entryHist.size() - 1) + ']'); - - return; // Skip current partition. - } + mvccPreloadEntry(cctx, node, entryHist, topVer, p); //TODO: IGNITE-11330: Update metrics for touched cache only. for (GridCacheContext ctx : grp.caches()) { @@ -987,13 +986,7 @@ else if (cctx.isNear()) cctx = cctx.dhtCache().context(); } - if (!preloadEntry(node, p, entry, topVer, cctx, null)) { - if (log.isTraceEnabled()) - log.trace("Got entries for invalid partition during " + - "preloading (will skip) [p=" + p + ", entry=" + entry + ']'); - - return; - } + preloadEntry(node, p, entry, topVer, cctx, null); //TODO: IGNITE-11330: Update metrics for touched cache only. for (GridCacheContext ctx : grp.caches()) { @@ -1057,8 +1050,11 @@ private void preloadEntriesBatched( if (cctx.isNear()) cctx = cctx.dhtCache().context(); - if (!preloadEntry(from, p, info, topVer, cctx, row)) - return; + if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) { + // Remove pre-created data row. + grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(). + removeRow(row.link(), grp.statisticsHolderData()); + } //TODO: IGNITE-11330: Update metrics for touched cache only. for (GridCacheContext cctx0 : grp.caches()) { @@ -1069,26 +1065,19 @@ private void preloadEntriesBatched( } finally { // Remove all unprocessed rows on error. - while (rowsIter != null && rowsIter.hasNext()) - cleanupRow(rowsIter.next()); + while (rowsIter != null && rowsIter.hasNext()) { + CacheDataRow row = rowsIter.next(); + + // Remove pre-created data row. + grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(). + removeRow(row.link(), grp.statisticsHolderData()); + } ctx.database().checkpointReadUnlock(); } } } - /** - * Remove row from data store. - * - * @param row Row to remove. - * @throws IgniteCheckedException If failed. - */ - private void cleanupRow(CacheDataRow row) throws IgniteCheckedException { - RowStore rowStore = grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(); - - rowStore.removeRow(row.link(), grp.statisticsHolderData()); - } - /** * Adds {@code entry} to partition {@code p}. * @@ -1098,7 +1087,7 @@ private void cleanupRow(CacheDataRow row) throws IgniteCheckedException { * @param topVer Topology version. * @param cctx Cache context. * @param row Pre-created data row, associated with this cache entry. - * @return {@code False} if partition has become invalid during preloading. + * @return {@code True} if the initial value was set for the specified cache entry. * @throws IgniteInterruptedCheckedException If interrupted. */ private boolean preloadEntry( @@ -1111,8 +1100,6 @@ private boolean preloadEntry( ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); - boolean updated = false; - try { GridCacheEntryEx cached = null; @@ -1125,7 +1112,7 @@ private boolean preloadEntry( } if (preloadPred == null || preloadPred.apply(entry)) { - if (updated = cached.initialValue( + if (cached.initialValue( entry.value(), entry.version(), cctx.mvccEnabled() ? ((MvccVersionAware)entry).mvccVersion() : null, @@ -1146,6 +1133,8 @@ private boolean preloadEntry( cctx.events().addEvent(cached.partition(), cached.key(), cctx.localNodeId(), null, null, null, EVT_CACHE_REBALANCE_OBJECT_LOADED, entry.value(), true, null, false, null, null, null, true); + + return true; } else { cached.touch(); // Start tracking. @@ -1161,12 +1150,6 @@ private boolean preloadEntry( log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" + cached.key() + ", part=" + p + ']'); } - catch (GridDhtInvalidPartitionException ignored) { - if (log.isDebugEnabled()) - log.debug("Partition became invalid during rebalancing (will ignore): " + p); - - return false; - } } catch (IgniteInterruptedCheckedException e) { throw e; @@ -1174,12 +1157,9 @@ private boolean preloadEntry( catch (IgniteCheckedException e) { throw new IgniteCheckedException("Failed to cache rebalanced entry (will stop rebalancing) [local=" + ctx.localNode() + ", node=" + from.id() + ", key=" + entry.key() + ", part=" + p + ']', e); - } finally { - if (!updated && row != null) - cleanupRow(row); } - return true; + return false; } /** @@ -1190,7 +1170,7 @@ private boolean preloadEntry( * @param history Mvcc entry history. * @param topVer Topology version. * @param p Partition id. - * @return {@code False} if partition has become invalid during preloading. + * @return {@code True} if the initial value was set for the specified cache entry. * @throws IgniteInterruptedCheckedException If interrupted. */ private boolean mvccPreloadEntry( @@ -1223,6 +1203,8 @@ private boolean mvccPreloadEntry( cctx.events().addEvent(cached.partition(), cached.key(), cctx.localNodeId(), null, null, null, EVT_CACHE_REBALANCE_OBJECT_LOADED, null, true, null, false, null, null, null, true); + + return true; } else { cached.touch(); // Start tracking. @@ -1237,12 +1219,6 @@ private boolean mvccPreloadEntry( log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" + cached.key() + ", part=" + p + ']'); } - catch (GridDhtInvalidPartitionException ignored) { - if (log.isDebugEnabled()) - log.debug("Partition became invalid during rebalancing (will ignore): " + p); - - return false; - } } catch (IgniteInterruptedCheckedException | ClusterTopologyCheckedException e) { throw e; @@ -1252,7 +1228,7 @@ private boolean mvccPreloadEntry( ctx.localNode() + ", node=" + from.id() + ", key=" + info.key() + ", part=" + p + ']', e); } - return true; + return false; } /** From 68d4db2ac9fe24c2700ec34a30d4dea38d80b693 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Mon, 24 Jun 2019 15:48:22 +0300 Subject: [PATCH 37/50] IGNITE-11584 Minor. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 47f49fed55ee71..231c1268fb14b4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1068,7 +1068,6 @@ private void preloadEntriesBatched( while (rowsIter != null && rowsIter.hasNext()) { CacheDataRow row = rowsIter.next(); - // Remove pre-created data row. grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(). removeRow(row.link(), grp.statisticsHolderData()); } From 30ea5a07226ad2d02538b91ef15907e7209da00e Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 11:48:51 +0300 Subject: [PATCH 38/50] IGNITE_11584 Minor. --- .../cache/IgniteCacheOffheapManager.java | 4 ++-- .../cache/IgniteCacheOffheapManagerImpl.java | 18 +++++++++--------- .../preloader/GridDhtPartitionDemander.java | 2 +- .../persistence/GridCacheOffheapManager.java | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 84b4d08b22a69b..950398054f1aa6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -199,7 +199,7 @@ public void invoke(GridCacheContext cctx, KeyCacheObject key, GridDhtLocalPartit * @return Created rows. * @throws IgniteCheckedException If failed. */ - public Collection storeAll( + public Collection insertAll( GridDhtLocalPartition part, Collection entries ) throws IgniteCheckedException; @@ -751,7 +751,7 @@ void update( * @return Created rows. * @throws IgniteCheckedException If failed. */ - public Collection storeAll( + public Collection insertAll( Collection entries ) throws IgniteCheckedException; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index a36337547fc3b3..2b4caa2a078375 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -447,14 +447,6 @@ private Iterator cacheData(boolean primary, boolean backup, Affi dataStore(part).invoke(cctx, key, c); } - /** {@inheritDoc} */ - @Override public Collection storeAll( - GridDhtLocalPartition part, - Collection entries - ) throws IgniteCheckedException { - return dataStore(part).storeAll(entries); - } - /** {@inheritDoc} */ @Override public void update( GridCacheContext cctx, @@ -470,6 +462,14 @@ private Iterator cacheData(boolean primary, boolean backup, Affi dataStore(part).update(cctx, key, val, ver, expireTime, oldRow); } + /** {@inheritDoc} */ + @Override public Collection insertAll( + GridDhtLocalPartition part, + Collection entries + ) throws IgniteCheckedException { + return dataStore(part).insertAll(entries); + } + /** {@inheritDoc} */ @Override public boolean mvccInitialValue( GridCacheMapEntry entry, @@ -1703,7 +1703,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } /** {@inheritDoc} */ - @Override public Collection storeAll( + @Override public Collection insertAll( Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 231c1268fb14b4..2b20dd85ea53ec 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1039,7 +1039,7 @@ private void preloadEntriesBatched( grp.shared().database().ensureFreeSpace(grp.dataRegion()); // Create data rows on data pages before getting locks on cache entries. - rowsIter = grp.offheap().storeAll(part, updates).iterator(); + rowsIter = grp.offheap().insertAll(part, updates).iterator(); for (GridCacheEntryInfo info : batch) { CacheDataRow row = info.value() == null ? null : rowsIter.next(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 87368b95f22878..9c6b4569849f47 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2402,14 +2402,14 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { } /** {@inheritDoc} */ - @Override public Collection storeAll( + @Override public Collection insertAll( Collection entries ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); CacheDataStore delegate = init0(false); - return delegate.storeAll(entries); + return delegate.insertAll(entries); } /** {@inheritDoc} */ From a9eaa6ad109fc03c3b0c3702813998978cca8ad4 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 12:33:22 +0300 Subject: [PATCH 39/50] IGNITE_11584 Code cleanup. --- .../preloader/GridDhtPartitionDemander.java | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 2b20dd85ea53ec..4657c53634e6ef 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1033,45 +1033,43 @@ private void preloadEntriesBatched( try { GridDhtLocalPartition part = grp.topology().localPartition(p); - // Filter NULL values (this means we need to remove the cache entry). - Collection updates = F.view(batch, info -> info.value() != null); + try { + // Filter NULL values (this means we need to remove the cache entry). + Collection updates = F.view(batch, info -> info.value() != null); - grp.shared().database().ensureFreeSpace(grp.dataRegion()); + grp.shared().database().ensureFreeSpace(grp.dataRegion()); - // Create data rows on data pages before getting locks on cache entries. - rowsIter = grp.offheap().insertAll(part, updates).iterator(); + // Create data rows on data pages before getting locks on cache entries. + rowsIter = grp.offheap().insertAll(part, updates).iterator(); - for (GridCacheEntryInfo info : batch) { - CacheDataRow row = info.value() == null ? null : rowsIter.next(); + for (GridCacheEntryInfo info : batch) { + CacheDataRow row = info.value() == null ? null : rowsIter.next(); - GridCacheContext cctx = - grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); + GridCacheContext cctx = + grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - if (cctx.isNear()) - cctx = cctx.dhtCache().context(); + if (cctx.isNear()) + cctx = cctx.dhtCache().context(); - if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) { - // Remove pre-created data row. - grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(). - removeRow(row.link(), grp.statisticsHolderData()); - } + if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) { + // Remove pre-created data row. + part.dataStore().rowStore().removeRow(row.link(), grp.statisticsHolderData()); + } - //TODO: IGNITE-11330: Update metrics for touched cache only. - for (GridCacheContext cctx0 : grp.caches()) { - if (cctx0.statisticsEnabled()) - cctx0.cache().metrics0().onRebalanceKeyReceived(); + //TODO: IGNITE-11330: Update metrics for touched cache only. + for (GridCacheContext cctx0 : grp.caches()) { + if (cctx0.statisticsEnabled()) + cctx0.cache().metrics0().onRebalanceKeyReceived(); + } } } + finally { + // Remove all unprocessed rows. + while (rowsIter != null && rowsIter.hasNext()) + part.dataStore().rowStore().removeRow(rowsIter.next().link(), grp.statisticsHolderData()); + } } finally { - // Remove all unprocessed rows on error. - while (rowsIter != null && rowsIter.hasNext()) { - CacheDataRow row = rowsIter.next(); - - grp.offheap().dataStore(grp.topology().localPartition(row.partition())).rowStore(). - removeRow(row.link(), grp.statisticsHolderData()); - } - ctx.database().checkpointReadUnlock(); } } From 9f67bc1f67058eec5245042bc914a2e7c60c8a98 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 12:36:06 +0300 Subject: [PATCH 40/50] IGNITE-11584 Code cleanup. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 4657c53634e6ef..c131e5969a9d89 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1051,10 +1051,8 @@ private void preloadEntriesBatched( if (cctx.isNear()) cctx = cctx.dhtCache().context(); - if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) { - // Remove pre-created data row. + if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) part.dataStore().rowStore().removeRow(row.link(), grp.statisticsHolderData()); - } //TODO: IGNITE-11330: Update metrics for touched cache only. for (GridCacheContext cctx0 : grp.caches()) { From 4e2872a7c92f388bb18cb7ccd4baba0b33868e63 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 15:21:53 +0300 Subject: [PATCH 41/50] IGNITE-11584 Minor. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index c131e5969a9d89..ceb6cfde7120e3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -897,7 +897,7 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node ctx.database().checkpointReadLock(); try { - for (int i = 0; i < 100; i++) { + for (int i = 0; i < CHECKPOINT_THRESHOLD; i++) { boolean hasMore = infos.hasNext(); assert hasMore || !entryHist.isEmpty(); From 63c199e00978fea22d0a9952b70ae0f0660d45c6 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 15:37:42 +0300 Subject: [PATCH 42/50] IGNITE-11584 Redundant call. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index ceb6cfde7120e3..6cb5e0b3f08b0e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1037,8 +1037,6 @@ private void preloadEntriesBatched( // Filter NULL values (this means we need to remove the cache entry). Collection updates = F.view(batch, info -> info.value() != null); - grp.shared().database().ensureFreeSpace(grp.dataRegion()); - // Create data rows on data pages before getting locks on cache entries. rowsIter = grp.offheap().insertAll(part, updates).iterator(); From 99d904adaf64e5196402fb2df0bd472549e1e125 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 17:39:09 +0300 Subject: [PATCH 43/50] IGNITE-11584 Use subList instead of arraylist creation, redundant cctx removed --- .../cache/IgniteCacheOffheapManagerImpl.java | 15 +----- .../preloader/GridDhtPartitionDemander.java | 49 ++++++++++--------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 2b4caa2a078375..70c8336c9af5b7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1715,20 +1715,9 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo IoStatisticsHolder statHolder = grp.statisticsHolderData(); for (GridCacheEntryInfo info : infos) { - GridCacheContext cctx = - grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - - KeyCacheObject key = info.key(); - CacheObject val = info.value(); - - CacheObjectContext coCtx = cctx.cacheObjectContext(); - - key.valueBytes(coCtx); - val.valueBytes(coCtx); - int cacheId = grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID; - DataRow row = makeDataRow(key, val, info.version(), info.expireTime(), cacheId); + DataRow row = makeDataRow(info.key(), info.value(), info.version(), info.expireTime(), cacheId); rows.add(row); } @@ -2421,7 +2410,7 @@ private int cleanup0(GridCacheContext cctx, @Nullable List infos = e.getValue().infos().iterator(); + List infos = e.getValue().infos(); try { if (grp.mvccEnabled()) @@ -884,21 +884,23 @@ else if (isEnoughSpaceForData(grp.dataRegion(), supplyMsg.messageSize() * 2)) * @throws IgniteInterruptedCheckedException If interrupted. */ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p, - Iterator infos) throws IgniteCheckedException { - if (!infos.hasNext()) + Collection infos) throws IgniteCheckedException { + if (infos.isEmpty()) return; List entryHist = new ArrayList<>(); GridCacheContext cctx = grp.sharedGroup() ? null : grp.singleCacheContext(); + Iterator iter = infos.iterator(); + // Loop through all received entries and try to preload them. - while (infos.hasNext() || !entryHist.isEmpty()) { + while (iter.hasNext() || !entryHist.isEmpty()) { ctx.database().checkpointReadLock(); try { for (int i = 0; i < CHECKPOINT_THRESHOLD; i++) { - boolean hasMore = infos.hasNext(); + boolean hasMore = iter.hasNext(); assert hasMore || !entryHist.isEmpty(); @@ -907,7 +909,7 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node boolean flushHistory; if (hasMore) { - entry = (GridCacheMvccEntryInfo)infos.next(); + entry = (GridCacheMvccEntryInfo)iter.next(); GridCacheMvccEntryInfo prev = entryHist.isEmpty() ? null : entryHist.get(0); @@ -963,19 +965,21 @@ private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node * @throws IgniteInterruptedCheckedException If interrupted. */ private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p, - Iterator infos) throws IgniteCheckedException { + Iterable infos) throws IgniteCheckedException { GridCacheContext cctx = null; + Iterator iter = infos.iterator(); + // Loop through all received entries and try to preload them. - while (infos.hasNext()) { + while (iter.hasNext()) { ctx.database().checkpointReadLock(); try { for (int i = 0; i < CHECKPOINT_THRESHOLD; i++) { - if (!infos.hasNext()) + if (!iter.hasNext()) break; - GridCacheEntryInfo entry = infos.next(); + GridCacheEntryInfo entry = iter.next(); if (cctx == null || (grp.sharedGroup() && entry.cacheId() != cctx.cacheId())) { cctx = grp.sharedGroup() ? grp.shared().cacheContext(entry.cacheId()) : grp.singleCacheContext(); @@ -1012,19 +1016,13 @@ private void preloadEntriesBatched( AffinityTopologyVersion topVer, ClusterNode from, int p, - Iterator infos + List infos ) throws IgniteCheckedException { - while (infos.hasNext()) { - List batch = new ArrayList<>(CHECKPOINT_THRESHOLD); - - while (infos.hasNext() && batch.size() < CHECKPOINT_THRESHOLD) { - GridCacheEntryInfo info = infos.next(); - - GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); + int batchOff = 0; - if (cctx != null) - batch.add(info); - } + while (batchOff < infos.size()) { + List batch = + infos.subList(batchOff, Math.min(infos.size(), batchOff += CHECKPOINT_THRESHOLD)); Iterator rowsIter = null; @@ -1038,7 +1036,7 @@ private void preloadEntriesBatched( Collection updates = F.view(batch, info -> info.value() != null); // Create data rows on data pages before getting locks on cache entries. - rowsIter = grp.offheap().insertAll(part, updates).iterator(); + rowsIter = part.dataStore().insertAll(updates).iterator(); for (GridCacheEntryInfo info : batch) { CacheDataRow row = info.value() == null ? null : rowsIter.next(); @@ -1046,12 +1044,15 @@ private void preloadEntriesBatched( GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); - if (cctx.isNear()) + if (cctx != null && cctx.isNear()) cctx = cctx.dhtCache().context(); - if (!preloadEntry(from, p, info, topVer, cctx, row) && row != null) + if ((cctx == null || !preloadEntry(from, p, info, topVer, cctx, row)) && row != null) part.dataStore().rowStore().removeRow(row.link(), grp.statisticsHolderData()); + if (cctx == null) + continue; + //TODO: IGNITE-11330: Update metrics for touched cache only. for (GridCacheContext cctx0 : grp.caches()) { if (cctx0.statisticsEnabled()) From c94018f1bc2d8bcad3eb4de2fd804abe1374fe30 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 17:52:55 +0300 Subject: [PATCH 44/50] IGNITE-11584 Minor rework offheap. --- .../cache/IgniteCacheOffheapManager.java | 19 +++++-------------- .../cache/IgniteCacheOffheapManagerImpl.java | 15 ++++++--------- .../persistence/GridCacheOffheapManager.java | 9 +++++++++ 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 950398054f1aa6..485786cadd60bd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -191,19 +191,6 @@ public boolean expire(GridCacheContext cctx, IgniteInClosure2X insertAll( - GridDhtLocalPartition part, - Collection entries - ) throws IgniteCheckedException; - /** * @param cctx Cache context. * @param key Key. @@ -708,6 +695,11 @@ CacheDataRow createRow( long expireTime, @Nullable CacheDataRow oldRow) throws IgniteCheckedException; + /** + * @param row Row removed from cache. + */ + public void removeRow(CacheDataRow row) throws IgniteCheckedException; + /** * @param cctx Cache context. * @param cleanupRows Rows to cleanup. @@ -743,7 +735,6 @@ void update( long expireTime, @Nullable CacheDataRow oldRow) throws IgniteCheckedException; - /** * Put entries into the data store. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 70c8336c9af5b7..3940ec369d775c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -462,14 +462,6 @@ private Iterator cacheData(boolean primary, boolean backup, Affi dataStore(part).update(cctx, key, val, ver, expireTime, oldRow); } - /** {@inheritDoc} */ - @Override public Collection insertAll( - GridDhtLocalPartition part, - Collection entries - ) throws IgniteCheckedException { - return dataStore(part).insertAll(entries); - } - /** {@inheritDoc} */ @Override public boolean mvccInitialValue( GridCacheMapEntry entry, @@ -1722,7 +1714,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo rows.add(row); } - rowStore().addRows(rows, statHolder); + rowStore.addRows(rows, statHolder); Iterator iter = infos.iterator(); @@ -1771,6 +1763,11 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo return dataRow; } + /** {@inheritDoc} */ + @Override public void removeRow(CacheDataRow row) throws IgniteCheckedException { + rowStore.removeRow(row.link(), grp.statisticsHolderData()); + } + /** * @param key Cache key. * @param val Cache value. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 9c6b4569849f47..05d6fc882acb19 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2376,6 +2376,15 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { return delegate.createRow(cctx, key, val, ver, expireTime, oldRow); } + /** {@inheritDoc} */ + @Override public void removeRow(CacheDataRow row) throws IgniteCheckedException { + assert ctx.database().checkpointLockIsHeldByThread(); + + CacheDataStore delegate = init0(false); + + delegate.removeRow(row); + } + /** {@inheritDoc} */ @Override public int cleanup(GridCacheContext cctx, @Nullable List cleanupRows) throws IgniteCheckedException { From 25f28f621cdf8dc857c8d85b66e4ee3215dd873e Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 17:55:37 +0300 Subject: [PATCH 45/50] IGNITE-11584 Minor. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 908cdeb3152a73..0869039ad61458 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1048,7 +1048,7 @@ private void preloadEntriesBatched( cctx = cctx.dhtCache().context(); if ((cctx == null || !preloadEntry(from, p, info, topVer, cctx, row)) && row != null) - part.dataStore().rowStore().removeRow(row.link(), grp.statisticsHolderData()); + part.dataStore().removeRow(row); if (cctx == null) continue; From 7ece4b8a5a0d02e962c14bb5a938675b69649a4b Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 17:59:46 +0300 Subject: [PATCH 46/50] IGNITE-11584 Minor. --- .../distributed/dht/preloader/GridDhtPartitionDemander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 0869039ad61458..b04e6e0981ff6e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1063,7 +1063,7 @@ private void preloadEntriesBatched( finally { // Remove all unprocessed rows. while (rowsIter != null && rowsIter.hasNext()) - part.dataStore().rowStore().removeRow(rowsIter.next().link(), grp.statisticsHolderData()); + part.dataStore().removeRow(rowsIter.next()); } } finally { From eb2b88eb833680e301c4232c549b57a7d9230d9a Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 18:34:36 +0300 Subject: [PATCH 47/50] IGNITE-11584 Code cleanup. --- .../cache/IgniteCacheOffheapManager.java | 22 +++---- .../cache/IgniteCacheOffheapManagerImpl.java | 64 +++++++++---------- .../preloader/GridDhtPartitionDemander.java | 2 +- .../persistence/GridCacheOffheapManager.java | 6 +- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 485786cadd60bd..98673f5fbf6089 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -695,6 +695,17 @@ CacheDataRow createRow( long expireTime, @Nullable CacheDataRow oldRow) throws IgniteCheckedException; + /** + * Create data rows. + * + * @param infos Entry infos. + * @return Created rows. + * @throws IgniteCheckedException If failed. + */ + public Collection createRows( + Collection infos + ) throws IgniteCheckedException; + /** * @param row Row removed from cache. */ @@ -735,17 +746,6 @@ void update( long expireTime, @Nullable CacheDataRow oldRow) throws IgniteCheckedException; - /** - * Put entries into the data store. - * - * @param entries Entries. - * @return Created rows. - * @throws IgniteCheckedException If failed. - */ - public Collection insertAll( - Collection entries - ) throws IgniteCheckedException; - /** * @param cctx Cache context. * @param key Key. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 3940ec369d775c..5d51d4d073dc36 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1695,7 +1695,38 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } /** {@inheritDoc} */ - @Override public Collection insertAll( + @Override public CacheDataRow createRow( + GridCacheContext cctx, + KeyCacheObject key, + CacheObject val, + GridCacheVersion ver, + long expireTime, + @Nullable CacheDataRow oldRow) throws IgniteCheckedException { + int cacheId = grp.storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; + + DataRow dataRow = makeDataRow(key, val, ver, expireTime, cacheId); + + if (canUpdateOldRow(cctx, oldRow, dataRow) && rowStore.updateRow(oldRow.link(), dataRow, grp.statisticsHolderData())) + dataRow.link(oldRow.link()); + else { + CacheObjectContext coCtx = cctx.cacheObjectContext(); + + key.valueBytes(coCtx); + val.valueBytes(coCtx); + + rowStore.addRow(dataRow, grp.statisticsHolderData()); + } + + assert dataRow.link() != 0 : dataRow; + + if (grp.sharedGroup() && dataRow.cacheId() == CU.UNDEFINED_CACHE_ID) + dataRow.cacheId(cctx.cacheId()); + + return dataRow; + } + + /** {@inheritDoc} */ + @Override public Collection createRows( Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) @@ -1732,37 +1763,6 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo return rows; } - /** {@inheritDoc} */ - @Override public CacheDataRow createRow( - GridCacheContext cctx, - KeyCacheObject key, - CacheObject val, - GridCacheVersion ver, - long expireTime, - @Nullable CacheDataRow oldRow) throws IgniteCheckedException { - int cacheId = grp.storeCacheIdInDataPage() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; - - DataRow dataRow = makeDataRow(key, val, ver, expireTime, cacheId); - - if (canUpdateOldRow(cctx, oldRow, dataRow) && rowStore.updateRow(oldRow.link(), dataRow, grp.statisticsHolderData())) - dataRow.link(oldRow.link()); - else { - CacheObjectContext coCtx = cctx.cacheObjectContext(); - - key.valueBytes(coCtx); - val.valueBytes(coCtx); - - rowStore.addRow(dataRow, grp.statisticsHolderData()); - } - - assert dataRow.link() != 0 : dataRow; - - if (grp.sharedGroup() && dataRow.cacheId() == CU.UNDEFINED_CACHE_ID) - dataRow.cacheId(cctx.cacheId()); - - return dataRow; - } - /** {@inheritDoc} */ @Override public void removeRow(CacheDataRow row) throws IgniteCheckedException { rowStore.removeRow(row.link(), grp.statisticsHolderData()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index b04e6e0981ff6e..9f459910d60801 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1036,7 +1036,7 @@ private void preloadEntriesBatched( Collection updates = F.view(batch, info -> info.value() != null); // Create data rows on data pages before getting locks on cache entries. - rowsIter = part.dataStore().insertAll(updates).iterator(); + rowsIter = part.dataStore().createRows(updates).iterator(); for (GridCacheEntryInfo info : batch) { CacheDataRow row = info.value() == null ? null : rowsIter.next(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 05d6fc882acb19..14b9eebacf8a61 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2411,14 +2411,14 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { } /** {@inheritDoc} */ - @Override public Collection insertAll( - Collection entries + @Override public Collection createRows( + Collection infos ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); CacheDataStore delegate = init0(false); - return delegate.insertAll(entries); + return delegate.createRows(infos); } /** {@inheritDoc} */ From c84c727af7663c572a0251fab160fbaa0bd12ce8 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Tue, 25 Jun 2019 20:01:54 +0300 Subject: [PATCH 48/50] IGNITE-11584 Code cleanup. --- .../cache/IgniteCacheOffheapManager.java | 2 +- .../cache/IgniteCacheOffheapManagerImpl.java | 14 +++++--------- .../dht/preloader/GridDhtPartitionDemander.java | 2 +- .../cache/persistence/GridCacheOffheapManager.java | 2 +- .../processors/cache/persistence/RowStore.java | 2 +- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 98673f5fbf6089..64ca754d920a89 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -702,7 +702,7 @@ CacheDataRow createRow( * @return Created rows. * @throws IgniteCheckedException If failed. */ - public Collection createRows( + public Collection createRows( Collection infos ) throws IgniteCheckedException; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 5d51d4d073dc36..4bb83ed9a7e863 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1726,17 +1726,15 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } /** {@inheritDoc} */ - @Override public Collection createRows( + @Override public Collection createRows( Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) throw new NodeStoppingException("Operation has been cancelled (node is stopping)."); - List rows = new ArrayList<>(infos.size()); + List rows = new ArrayList<>(infos.size()); try { - IoStatisticsHolder statHolder = grp.statisticsHolderData(); - for (GridCacheEntryInfo info : infos) { int cacheId = grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID; @@ -1745,21 +1743,19 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo rows.add(row); } - rowStore.addRows(rows, statHolder); + rowStore.addRows(rows, grp.statisticsHolderData()); Iterator iter = infos.iterator(); if (grp.sharedGroup() && !grp.storeCacheIdInDataPage()) { - for (CacheDataRow row : rows) - ((DataRow)row).cacheId(iter.next().cacheId()); + for (DataRow row : rows) + row.cacheId(iter.next().cacheId()); } } finally { busyLock.leaveBusy(); } - assert rows.size() == infos.size(); - return rows; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 9f459910d60801..87d865a080193a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1024,7 +1024,7 @@ private void preloadEntriesBatched( List batch = infos.subList(batchOff, Math.min(infos.size(), batchOff += CHECKPOINT_THRESHOLD)); - Iterator rowsIter = null; + Iterator rowsIter = null; ctx.database().checkpointReadLock(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 14b9eebacf8a61..8391d83c076b58 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2411,7 +2411,7 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { } /** {@inheritDoc} */ - @Override public Collection createRows( + @Override public Collection createRows( Collection infos ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java index 85bcd6ddf45a9f..d172e13b308357 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java @@ -123,7 +123,7 @@ public void addRow(CacheDataRow row, IoStatisticsHolder statHolder) throws Ignit * @param statHolder Statistics holder to track IO operations. * @throws IgniteCheckedException If failed. */ - public void addRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { + public void addRows(Collection rows, IoStatisticsHolder statHolder) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread(); freeList.insertDataRows(rows, statHolder); From 20147a4310dff8001010633c4c983dcfce612e61 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 26 Jun 2019 11:48:09 +0300 Subject: [PATCH 49/50] IGNITE-11584 Code cleanup. --- .../cache/IgniteCacheOffheapManagerImpl.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 4bb83ed9a7e863..d1f031c7cbbd9a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1734,15 +1734,15 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo List rows = new ArrayList<>(infos.size()); - try { - for (GridCacheEntryInfo info : infos) { - int cacheId = grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID; - - DataRow row = makeDataRow(info.key(), info.value(), info.version(), info.expireTime(), cacheId); - - rows.add(row); - } + for (GridCacheEntryInfo info : infos) { + rows.add(makeDataRow(info.key(), + info.value(), + info.version(), + info.expireTime(), + grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID)); + } + try { rowStore.addRows(rows, grp.statisticsHolderData()); Iterator iter = infos.iterator(); @@ -1761,6 +1761,8 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo /** {@inheritDoc} */ @Override public void removeRow(CacheDataRow row) throws IgniteCheckedException { + assert row != null; + rowStore.removeRow(row.link(), grp.statisticsHolderData()); } From bd3db8079782a31bc66eddf8f929a35b212a5a23 Mon Sep 17 00:00:00 2001 From: pereslegin-pa Date: Wed, 26 Jun 2019 17:32:55 +0300 Subject: [PATCH 50/50] IGNITE-11584 Map experiment. --- .../cache/IgniteCacheOffheapManager.java | 2 +- .../cache/IgniteCacheOffheapManagerImpl.java | 24 ++++++++++++------- .../preloader/GridDhtPartitionDemander.java | 23 +++++++++++------- .../persistence/GridCacheOffheapManager.java | 2 +- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java index 64ca754d920a89..6cdd0540e5591a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java @@ -702,7 +702,7 @@ CacheDataRow createRow( * @return Created rows. * @throws IgniteCheckedException If failed. */ - public Collection createRows( + public Map createRows( Collection infos ) throws IgniteCheckedException; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index d1f031c7cbbd9a..56b7f5bef4e4e2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -23,9 +23,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; @@ -1726,23 +1728,29 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo } /** {@inheritDoc} */ - @Override public Collection createRows( + @Override public Map createRows( Collection infos ) throws IgniteCheckedException { if (!busyLock.enterBusy()) throw new NodeStoppingException("Operation has been cancelled (node is stopping)."); - List rows = new ArrayList<>(infos.size()); + // todo check hashmap + Map map = new LinkedHashMap<>(U.capacity(infos.size())); for (GridCacheEntryInfo info : infos) { - rows.add(makeDataRow(info.key(), - info.value(), - info.version(), - info.expireTime(), - grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID)); + DataRow row = info.value() == null ? null : + makeDataRow(info.key(), + info.value(), + info.version(), + info.expireTime(), + grp.storeCacheIdInDataPage() ? info.cacheId() : CU.UNDEFINED_CACHE_ID); + + map.put(info, row); } try { + Collection rows = F.view(map.values(), Objects::nonNull); + rowStore.addRows(rows, grp.statisticsHolderData()); Iterator iter = infos.iterator(); @@ -1756,7 +1764,7 @@ private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClo busyLock.leaveBusy(); } - return rows; + return map; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index 87d865a080193a..c2329347d3f5c9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1024,7 +1024,7 @@ private void preloadEntriesBatched( List batch = infos.subList(batchOff, Math.min(infos.size(), batchOff += CHECKPOINT_THRESHOLD)); - Iterator rowsIter = null; + Iterator> iter = null; ctx.database().checkpointReadLock(); @@ -1032,14 +1032,15 @@ private void preloadEntriesBatched( GridDhtLocalPartition part = grp.topology().localPartition(p); try { - // Filter NULL values (this means we need to remove the cache entry). - Collection updates = F.view(batch, info -> info.value() != null); - // Create data rows on data pages before getting locks on cache entries. - rowsIter = part.dataStore().createRows(updates).iterator(); + iter = part.dataStore().createRows(batch).entrySet().iterator(); + + while (iter.hasNext()) { + Map.Entry e = iter.next(); + + GridCacheEntryInfo info = e.getKey(); - for (GridCacheEntryInfo info : batch) { - CacheDataRow row = info.value() == null ? null : rowsIter.next(); + CacheDataRow row = e.getValue(); GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(info.cacheId()) : grp.singleCacheContext(); @@ -1062,8 +1063,12 @@ private void preloadEntriesBatched( } finally { // Remove all unprocessed rows. - while (rowsIter != null && rowsIter.hasNext()) - part.dataStore().removeRow(rowsIter.next()); + while (iter != null && iter.hasNext()) { + CacheDataRow row = iter.next().getValue(); + + if (row != null) + part.dataStore().removeRow(row); + } } } finally { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 8391d83c076b58..eb6ab252491f44 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -2411,7 +2411,7 @@ private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException { } /** {@inheritDoc} */ - @Override public Collection createRows( + @Override public Map createRows( Collection infos ) throws IgniteCheckedException { assert ctx.database().checkpointLockIsHeldByThread();