From commits-return-124567-archive-asf-public=cust-asf.ponee.io@ignite.apache.org Wed May 15 15:17:02 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id 7EB3A180621 for ; Wed, 15 May 2019 17:17:00 +0200 (CEST) Received: (qmail 19609 invoked by uid 500); 15 May 2019 15:16:38 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 19539 invoked by uid 99); 15 May 2019 15:16:38 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 15 May 2019 15:16:38 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 51AAD873B2; Wed, 15 May 2019 15:16:33 +0000 (UTC) Date: Wed, 15 May 2019 15:16:33 +0000 To: "commits@ignite.apache.org" Subject: [ignite] 01/01: Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: av@apache.org In-Reply-To: <155793339201.7601.13084246052995321043@gitbox.apache.org> References: <155793339201.7601.13084246052995321043@gitbox.apache.org> X-Git-Host: gitbox.apache.org X-Git-Repo: ignite X-Git-Refname: refs/heads/ignite-10078-jepsen1 X-Git-Reftype: branch X-Git-Rev: ee0ad939b9e56fbc11a7b3bd25bc5c315289915c X-Git-NotificationType: diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated Message-Id: <20190515151633.51AAD873B2@gitbox.apache.org> This is an automated email from the ASF dual-hosted git repository. av pushed a commit to branch ignite-10078-jepsen1 in repository https://gitbox.apache.org/repos/asf/ignite.git commit ee0ad939b9e56fbc11a7b3bd25bc5c315289915c Author: Anton Vinogradov AuthorDate: Wed May 15 18:14:53 2019 +0300 Squashed commit of the following: commit ca67cc531b1cdfd47f22e949716b43ebd3ae1ca2 Author: Aleksei Scherbakov Date: Wed May 15 15:51:54 2019 +0300 IGNITE-10078 Fix several issues. commit e1f5f4e33b25a6ac4fd1082749d8aae079759799 Author: Aleksei Scherbakov Date: Wed May 8 10:24:27 2019 +0300 IGNITE-10078 Minor codestyle fix. commit 2c0d7a3b837cc5ce7e2bbe5d712b156dc41a431f Author: Aleksei Scherbakov Date: Tue May 7 10:28:38 2019 +0300 IGNITE-10078 Fix codestyle issues. commit cda9e5090f5750b78a069b3848049560c56148b2 Author: Aleksei Scherbakov Date: Mon May 6 18:51:22 2019 +0300 IGNITE-10078 Disabled RollbackRecord for MVCC caches. commit 296abfbd886b9ad4fe488a6749803ee5fc9fcf47 Merge: 70b02dec4d 7a42592843 Author: Aleksei Scherbakov Date: Mon May 6 18:30:03 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java commit 70b02dec4dbb41851a976c0d7c41ab2ad065829c Author: Aleksei Scherbakov Date: Mon May 6 16:58:39 2019 +0300 IGNITE-10078 Fix in-memory partition clearing issue, reverted a revert of IGNITE-10799. commit 3689f9593a7b264617e7c95a309163c9e7ef8c6c Author: Alexey Scherbakov Date: Sun May 5 17:41:49 2019 +0300 Revert "IGNITE-10799 Optimize affinity recalculation in case of node join or leave - Fixes #6242." This reverts commit afe7933b156d51691997fefd251b76de5ea15e1a. # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java commit 83685aa98a1d67334c6d80f025e5495e6d8d9e61 Author: Alexey Scherbakov Date: Tue Apr 30 13:05:02 2019 +0300 IGNITE-10078 TC check. commit d7eeb7fc9fb273eac41b7c297688d65f3c582bbb Author: Alexey Scherbakov Date: Tue Apr 30 11:39:47 2019 +0300 IGNITE-10078 Revert to old initAffinityOnNodeJoin commit 04114b944d82409d2dcd13f89d4dd79297b87456 Author: Aleksei Scherbakov Date: Mon Apr 29 18:44:57 2019 +0300 IGNITE-10078 Fix concurrent isolated updater and tx mode. commit ec11a9e91b83beddf3a79e6de7484e04cbd1fea2 Author: Aleksei Scherbakov Date: Mon Apr 29 16:29:26 2019 +0300 IGNITE-10078 Cleanup. commit 4741ad3267d76e3a7a496926fff534b508f39a5c Merge: 4a44047cbe 2ad6c85a67 Author: Aleksei Scherbakov Date: Mon Apr 29 14:06:29 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java commit 4a44047cbe1f1e44d19e02a401d319799ac452ce Author: Alexey Scherbakov Date: Sun Apr 28 17:46:13 2019 +0300 IGNITE-10078 Fix issue with cache group name (not properly handled in test code). commit 15ea64f792f29db3dd88da66b1974df025e1bf2f Author: Alexey Scherbakov Date: Sun Apr 28 14:55:22 2019 +0300 IGNITE-10078 Fix issue with isolated updater. commit d05fb3f0971a62097d28ef52de1ecd41309d61d4 Author: Alexey Scherbakov Date: Sat Apr 27 15:30:50 2019 +0300 IGNITE-10078 Partial revert of affinity calculation optimization on node left. commit 1c4a20a7276eefc5f2da6decc580bef6eb1bbfd7 Author: Aleksei Scherbakov Date: Fri Apr 26 19:12:39 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java commit 349e8d6d6603fb6b82e3ba14b8178a7be0b70ece Merge: 19ca96fa9c a998b25828 Author: Aleksei Scherbakov Date: Fri Apr 26 19:11:43 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java commit 19ca96fa9ce8c25eed0d047b8d0f8a069e58a96e Author: Aleksei Scherbakov Date: Fri Apr 26 18:51:43 2019 +0300 IGNITE-10078 Minor. commit e2a44a3c989abe1db59759a0ed742f022f569a7f Author: Aleksei Scherbakov Date: Fri Apr 26 18:49:36 2019 +0300 IGNITE-10078 Final codestyle fix. commit 25dc10a2b87b65fb80df80ff331893a89cd177e9 Author: Aleksei Scherbakov Date: Fri Apr 26 17:39:42 2019 +0300 IGNITE-10078 Fix wrong late affinity calculation. commit a31aaa18abaed5f5e590ed4c7fc2a3d205a9f4f9 Author: Aleksei Scherbakov Date: Thu Apr 25 19:59:18 2019 +0300 IGNITE-10078 Cleanup. commit 7d41dba297ac11cf9ced030e634e05cd3aed641d Author: Aleksei Scherbakov Date: Thu Apr 25 19:16:37 2019 +0300 IGNITE-10078 Cleanup. commit cf11881fb1a5f22ca6624389ad661a3f7b9a4aa7 Author: Aleksei Scherbakov Date: Thu Apr 25 18:21:01 2019 +0300 IGNITE-10078 Cleanup. commit 3b265806d61a5d5b25f50c4920eeb858a196578a Author: Aleksei Scherbakov Date: Thu Apr 25 16:35:06 2019 +0300 IGNITE-10078 Cleanup. commit 03dbe7cd0fdbb969b38647b43fbbca9476b2c869 Author: Aleksei Scherbakov Date: Thu Apr 25 14:41:53 2019 +0300 IGNITE-10078 Fix CacheGroupTest scenarios with mixed tx-atomic caches in groups. commit 6980832cbf5dd00b964a9e2f6a87229f542a53e9 Author: Aleksei Scherbakov Date: Wed Apr 24 18:47:32 2019 +0300 IGNITE-10078 Fix issue with isolated updater in test. commit 6860fa3b3df0e1179ec63b55ba1ded4c79fcf61a Author: Aleksei Scherbakov Date: Wed Apr 24 18:01:35 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java # modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java commit be160d5edf77853de47a323b5519bc283aebc1dd Author: Aleksei Scherbakov Date: Wed Apr 24 15:05:44 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java # modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java commit 05e1df5d507bd0a6af302cd463cf14de00d09a98 Merge: 4ccae674c3 c2c0b148ae Author: Aleksei Scherbakov Date: Wed Apr 24 15:05:32 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java # modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java commit 4ccae674c3ad14e994d4c3600e2f9bed3224f34a Author: Aleksei Scherbakov Date: Wed Apr 24 14:50:00 2019 +0300 IGNITE-10078 Cleanup TODOs. commit 6223cb2518b00defd6f47ebfef1feae7ded16fbb Author: Aleksei Scherbakov Date: Tue Apr 23 20:35:40 2019 +0300 IGNITE-10078 Cleanup TODOs. commit 3e7da5ab7867f08052676f1939c903dde35ef71e Merge: e48ce33e4d db285122a7 Author: Aleksei Scherbakov Date: Tue Apr 23 15:54:29 2019 +0300 Merge branch 'ignite-10078' of https://github.com/gridgain/apache-ignite into ignite-10078 commit e48ce33e4d000221aebc78ec0e053f3c096f00c6 Author: Aleksei Scherbakov Date: Tue Apr 23 15:53:41 2019 +0300 IGNITE-10078 Implemented "old mode" for atomic or mixed cache groups. commit db285122a76c86f9f0a171ad64728473ead69468 Author: Alexey Scherbakov Date: Mon Apr 22 23:34:03 2019 +0300 IGNITE-10078 Fix NPE in exchange future. commit 3cc00ab8f6b77982c3da8c82f20f014250a0929c Author: Aleksei Scherbakov Date: Mon Apr 22 17:58:01 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite3.java commit 9062305f0ed4860904d5c4a6a24dd181e8af8dc1 Merge: 60fc9b26d3 d6827886a4 Author: Aleksei Scherbakov Date: Mon Apr 22 17:57:48 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite3.java commit 60fc9b26d3dfd798611094bc67d2047a6aa5da23 Author: Alexey Scherbakov Date: Sun Apr 21 18:56:16 2019 +0300 IGNITE-10078 Fix issue with re-rebalance of moving partition on coordinator. commit 7b2b7dbf074841090bebb9dc48f5b02121172fad Author: Aleksei Scherbakov Date: Fri Apr 19 19:30:05 2019 +0300 IGNITE-10078 Proper fix for clearing partition + full rebalance. commit 165a4d17ec97b92f90ea4a19a89108bc1589b1e3 Author: Aleksei Scherbakov Date: Thu Apr 18 19:50:14 2019 +0300 IGNITE-10078 Cleanup - wip. commit b8a97b78a2ab81eeb8a5136b58bb31d99d0b91e8 Author: Aleksei Scherbakov Date: Thu Apr 18 18:48:57 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/DefaultFreeList.java commit 030b4606a938d41151303878a71396ef0f5eb38c Merge: 204202826e 280894315f Author: Aleksei Scherbakov Date: Thu Apr 18 18:44:15 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/DefaultFreeList.java commit 204202826ee5a7cc261d8b8107b51f26dc0e7ea3 Author: Aleksei Scherbakov Date: Thu Apr 18 17:51:14 2019 +0300 IGNITE-10078 Minor style. commit 13a89dd7aa3c472cef427e84bc2c63ceb5401865 Author: Aleksei Scherbakov Date: Thu Apr 18 17:23:58 2019 +0300 IGNITE-10078 More logging for flaky test CacheRentingStateRepair. commit 60da22ae7ca84b0e83fc7d235d2a8bd07cb92292 Author: Aleksei Scherbakov Date: Thu Apr 18 17:21:26 2019 +0300 IGNITE-10078 More logging for flaky test CacheRentingStateRepair. commit 069842550d674e7fa28938b4f3f61389b174ffd2 Author: Aleksei Scherbakov Date: Thu Apr 18 13:17:41 2019 +0300 IGNITE-10078 Extending expected exceptions list in continuous restarts test. commit f779e293dc687f50e0db4645a7c7f9ba6d234907 Author: Aleksei Scherbakov Date: Thu Apr 18 12:01:44 2019 +0300 IGNITE-10078 Extending expected exceptions list in continuous restarts test. commit a5609b1585fa6efec058736b1c489776532ad229 Author: Aleksei Scherbakov Date: Wed Apr 17 20:20:30 2019 +0300 IGNITE-10078 Ignore flaky test. commit 88429164db2405d920418390fe88b358654bdbc1 Author: Aleksei Scherbakov Date: Wed Apr 17 20:15:55 2019 +0300 IGNITE-10078 Fix data store init on activation. commit 41c0ef30f54d7378a1dccef5b94ff2b89f847715 Author: Aleksei Scherbakov Date: Mon Apr 15 20:02:12 2019 +0300 IGNITE-10078 In-place update fix, improved logging for rebalance. commit d7686fee1b8285b89cacbd561c53721679568984 Author: Alexey Scherbakov Date: Sun Apr 14 21:54:32 2019 +0300 IGNITE-10078 Disabled debugging counter for TC run. commit 31df1cbc6890a94e82796dc3558693caef0ab665 Author: Alexey Scherbakov Date: Sun Apr 14 19:31:03 2019 +0300 IGNITE-10078 Valid late assignment switch. commit cbd4e0cfc0b00858412f97962998e3a22e64d6e6 Author: Aleksei Scherbakov Date: Fri Apr 12 19:07:22 2019 +0300 IGNITE-10078 minor renaming. commit 27c5c8e4904430a8733fa0e0e750ed23b8c9f691 Author: Aleksei Scherbakov Date: Fri Apr 12 18:14:17 2019 +0300 IGNITE-10078 Fix for force clearing partition if was in moving state before rebalance. commit 40e88354d64aad4f44e76faf5d3d0be4278efd14 Author: Aleksei Scherbakov Date: Fri Apr 12 15:30:50 2019 +0300 IGNITE-10078 Desync on full rebalance reproducer. commit b7a9dd115711b15fb04a8cf2e6859aeab246d105 Author: Aleksei Scherbakov Date: Thu Apr 11 15:07:33 2019 +0300 IGNITE-10078 Additional logging. commit 4a4979c57e2ac876e455c1742ed86e2aa1512bf5 Author: Aleksei Scherbakov Date: Tue Apr 9 19:20:13 2019 +0300 IGNITE-10078 Additional logging. commit 9ca272222ebc80f87b08c9527db42a2b6352813b Author: Aleksei Scherbakov Date: Tue Apr 9 18:43:40 2019 +0300 IGNITE-10078 Desync fix test 3. commit a21cce2b2922b71c8cc559ee7be31c3b82ea9636 Author: Aleksei Scherbakov Date: Tue Apr 9 18:21:42 2019 +0300 IGNITE-10078 Desync fix test 2. commit aea2d5cdf02adc11ce7870b7d2515e8a10330e5a Author: Aleksei Scherbakov Date: Tue Apr 9 15:49:49 2019 +0300 IGNITE-10078 Desync fix test. commit a27761d262f840890cd01b57ff16e537596fd114 Author: Aleksei Scherbakov Date: Mon Apr 8 19:34:51 2019 +0300 IGNITE-10078 Reproducer for desync + hist rebalance issue. commit 048b0a68583ccc1de94afa6f7961bcbd9ddb14b6 Author: Aleksei Scherbakov Date: Mon Apr 8 18:32:22 2019 +0300 IGNITE-10078 Fixed concurrency issue. commit 109ef03f46b5075612b789afe4ab3a1e6ee675f8 Author: Aleksei Scherbakov Date: Fri Apr 5 18:01:58 2019 +0300 IGNITE-10078 Cleaned up tests. commit d7a48d6873ab3075d1bafcd1699512a9aabd1cb3 Author: Aleksei Scherbakov Date: Fri Apr 5 16:30:29 2019 +0300 IGNITE-10078 Disable removal from deferred queue on rebalance by ttl. commit ee3306749d993d7534ba2abb2f29a06cf48ca219 Author: Aleksei Scherbakov Date: Fri Apr 5 14:18:26 2019 +0300 IGNITE-10078 Next fix try. commit 29565048837a952928e7a3e4796161677dda2cdc Author: Aleksei Scherbakov Date: Fri Apr 5 14:16:16 2019 +0300 IGNITE-10078 Next fix try. commit 8ee04285948e3d3f1b9e913aa41c7cb4b78e3ada Author: Aleksei Scherbakov Date: Fri Apr 5 13:56:45 2019 +0300 IGNITE-10078 Reproduced desync issue. commit 560341ec7fc665e3bc08eebe817eb6b1e20d41df Author: Aleksei Scherbakov Date: Fri Apr 5 11:47:20 2019 +0300 IGNITE-10078 Test deferred queue fix. commit b9ab5bdde2babd2e52c0d06f36d0900feda0049e Author: Aleksei Scherbakov Date: Thu Apr 4 19:04:18 2019 +0300 IGNITE-10078 WAL reader. commit a55854aa6bda5bbd4c0ae5bd3303c8808ae2a984 Author: Aleksei Scherbakov Date: Thu Apr 4 17:51:28 2019 +0300 IGNITE-10078 Added test for scenario when missed update is received after checkpoint. commit 5bc28b8e392b7202da1cfa96fd53830a96b404c7 Author: Aleksei Scherbakov Date: Thu Apr 4 17:51:09 2019 +0300 IGNITE-10078 Added test for scenario when missed update is received after checkpoint. commit 8019f91cf0d4619225dbeb5a20d54d29d4a74d1b Author: Aleksei Scherbakov Date: Wed Apr 3 20:15:52 2019 +0300 IGNITE-10078 Fix logical recovery issue with zero counter. commit 63eff8ed8160b9498cb38e3f64125a237e3de219 Author: Aleksei Scherbakov Date: Wed Apr 3 18:47:14 2019 +0300 IGNITE-10078 Use rollbackrecord on logical recovery to avoid unnecessary rebalancing. commit c0e7d577149fdb65e918af6d3a33423ce7edcb9a Author: Aleksei Scherbakov Date: Tue Apr 2 11:54:53 2019 +0300 IGNITE-10078 Fix naming for out-of-order updates. commit 2f85c2c91ea3726dbcfc73294189db1bd5a28742 Author: Aleksei Scherbakov Date: Tue Apr 2 11:44:20 2019 +0300 IGNITE-10078 Pre-create partition only if having valid state. commit eb911681d38e9ef437428c31e6e304ea22276376 Author: Aleksei Scherbakov Date: Tue Apr 2 10:50:24 2019 +0300 IGNITE-10078 Minor. commit 9eeb2dcc0eb6e6e27139935bcb9e240cfb3b110d Author: Aleksei Scherbakov Date: Mon Apr 1 20:18:33 2019 +0300 IGNITE-10078 Added assertion for sequential partition. commit 46a89b1dd65443d9f9f180e2438cb458a52d3577 Merge: ab14a8ec9f 963a40b7aa Author: Aleksei Scherbakov Date: Mon Apr 1 14:55:09 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit ab14a8ec9f56d1b97f274f54d0dbbfae66fe7ccd Author: Aleksei Scherbakov Date: Mon Apr 1 14:53:58 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java commit 196b9f2bf83b44e55cfc9f599aedf7b7cd1da25e Merge: 4b9301c439 9a9c817f8f Author: Aleksei Scherbakov Date: Mon Apr 1 14:53:38 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java commit 4b9301c43919c50472f96a1b529eef66b96daeeb Author: Aleksei Scherbakov Date: Mon Apr 1 12:08:11 2019 +0300 IGNITE-10078 Minor code cleanup. commit 237ffd0b1b9084ec73af395d8a072c1173fec2bf Author: Alexey Scherbakov Date: Sun Mar 31 19:32:49 2019 +0300 IGNITE-10078 Partition update counter debugging. commit c832ab48533547cb3179d3b537c7c9061b8b6642 Author: Alexey Scherbakov Date: Sun Mar 24 15:41:46 2019 +0300 IGNITE-10078 Fix update counter overlap issue. commit 2a8f9dd5366efb2b6a49ef8b066e3971eb3a6d5f Author: Aleksei Scherbakov Date: Fri Mar 22 19:22:56 2019 +0300 IGNITE-10078 Cleanup TxPartitionCouterState* tests. commit 473f7b7a1ea7b0a2ae19272bf482354f5f1309c5 Author: Aleksei Scherbakov Date: Fri Mar 22 17:56:30 2019 +0300 IGNITE-10078 Cleanup TxPartitionCouterState* tests. commit 7021afe4655cc9458401e90475fc6920134f4f4e Author: Aleksei Scherbakov Date: Fri Mar 22 16:22:46 2019 +0300 IGNITE-10078 Cleanup TxPartitionCouterState* tests. commit 6184535280a7365466691cd8831980f7c03f5df5 Author: Alexey Scherbakov Date: Thu Mar 21 23:02:03 2019 +0300 IGNITE-10078 Fix wrong test. commit 20ab7b99ff73c811a7e354e3cc63a910bdf17eb0 Author: Aleksei Scherbakov Date: Thu Mar 21 19:09:33 2019 +0300 IGNITE-10078 Fixed test. commit ebe1e51e286dfb71683fbbf92d7d7733a6df8b29 Author: Aleksei Scherbakov Date: Thu Mar 21 16:25:24 2019 +0300 IGNITE-10078 Fixed new record type and gaps shring issues. commit 556fe9070d7f4a74cd7c08fd6dcb69e0d7787ecf Author: Aleksei Scherbakov Date: Thu Mar 21 11:38:13 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java # modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java commit 2c876b7a0063ea3fcff80cbf16dd66b63c825713 Merge: f802c53c0c b221ab8dd1 Author: Aleksei Scherbakov Date: Thu Mar 21 11:37:24 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java # modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java commit f802c53c0c15face1035d3616ca4ec3231dfa171 Author: Aleksei Scherbakov Date: Wed Mar 20 19:42:08 2019 +0300 IGNITE-10078 Fixed issues in partition metastore. Removed copypaste. commit 2400675fe8698dfc364a7efba515a599c07f3351 Author: Aleksei Scherbakov Date: Tue Mar 19 20:52:05 2019 +0300 IGNITE-10078 Add partition metastore. commit 9b1a06b2e24881a34052b73c6266dc61bf8f2bbb Author: Aleksei Scherbakov Date: Tue Mar 19 19:29:39 2019 +0300 IGNITE-10078 Add partition metastore. commit 59aa188edf14dc51186b457afb309bf032f272b6 Author: Aleksei Scherbakov Date: Tue Mar 19 19:13:38 2019 +0300 IGNITE-10078 Add partition metastore. commit 55c6f7cbba1df258704772264302cd2c6da5b0b0 Author: Aleksei Scherbakov Date: Mon Mar 18 20:03:50 2019 +0300 IGNITE-10078 Fix wrong (partially) assertion. commit ac2cff4c742cccd0287434fc06cf02daa7ff418b Author: Aleksei Scherbakov Date: Mon Mar 18 14:38:30 2019 +0300 IGNITE-10078 Fix metastore default partition. commit 725c0ea33a31b8cc87b510dc7f0ecf0e63247f68 Author: Aleksei Scherbakov Date: Mon Mar 18 11:27:18 2019 +0300 IGNITE-10078 Minor. commit 7af2cef3dbae5dd7da355986c321019a836f88e4 Author: Alexey Scherbakov Date: Mon Mar 18 00:32:24 2019 +0300 IGNITE-10078 Fix freelist issue. commit 0dc46d6296a603c2bba93e6d055f60457cb750e4 Author: Alexey Scherbakov Date: Sun Mar 17 20:50:46 2019 +0300 IGNITE-10078 Fix freelist issue. commit 73880630a11733cecf80b49b661576bac9e49aff Author: Aleksei Scherbakov Date: Fri Mar 15 19:15:31 2019 +0300 IGNITE-10078 Fix concurrent modification issue for gaps. commit 7880d721d8543c01cc40ff766c268133fcb02741 Author: Aleksei Scherbakov Date: Fri Mar 15 16:11:48 2019 +0300 IGNITE-10078 Code style. commit 304ea22552a8f545ffbcdea1618a42f56bec9814 Merge: cff5b4e4d0 ee172d2604 Author: Aleksei Scherbakov Date: Fri Mar 15 15:53:13 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java commit cff5b4e4d05bbfcaff84533c6798460c9be12878 Author: Aleksei Scherbakov Date: Fri Mar 15 15:43:30 2019 +0300 IGNITE-10078 FreeList refactoring. commit 70024029c8f27c76ed70d72867c3220ab9c21112 Author: Aleksei Scherbakov Date: Fri Mar 15 15:25:47 2019 +0300 IGNITE-10078 FreeList refactoring. commit 843c84b5994697f3f01d1eb2039680a0c0384139 Author: Aleksei Scherbakov Date: Thu Mar 14 20:31:54 2019 +0300 IGNITE-10078 FreeList refactoring. commit eb6e9a303947d831419fc8cb5750b3e4a38102c6 Author: Aleksei Scherbakov Date: Tue Mar 12 20:05:34 2019 +0300 IGNITE-10078 FreeList refactoring. commit 1530626b8f4836a5f2b6b80a467d25f85a5c468d Author: Aleksei Scherbakov Date: Tue Mar 12 14:19:56 2019 +0300 IGNITE-10078 FreeList refactoring. commit 7feed34f26b467225beb4515d71d0ec97decba0b Author: Aleksei Scherbakov Date: Tue Mar 12 14:18:05 2019 +0300 IGNITE-10078 FreeList refactoring. commit 76d367098ec8854b2c9d0121c1d798bd8f2e3724 Author: Alexey Scherbakov Date: Mon Mar 11 21:52:57 2019 +0300 IGNITE-10078 Refactoring freelist to work with any Storable. commit b747416898445e5f502f404ba2973867872f1186 Author: Alexey Scherbakov Date: Mon Mar 11 16:51:48 2019 +0300 IGNITE-10078 Added local cache tx test to ignored for MVCC. commit 20634d470e922fa2a5268cec4be49ddf3e4bf8a9 Author: Aleksei Scherbakov Date: Mon Mar 11 13:31:58 2019 +0300 IGNITE-10078 Javadoc cleanup. commit 50394ae2d2b535a4f0757133e4c7508293cd956d Merge: 7ace0b5be5 3e80ca44e4 Author: Aleksei Scherbakov Date: Mon Mar 11 12:11:46 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 7ace0b5be5ee5d1026b2fe9fe7267de6ecd38a97 Author: Aleksei Scherbakov Date: Mon Mar 11 12:04:08 2019 +0300 IGNITE-10078 Removed local cache tx test from MVCC suite. commit 96c492bc642fb0ff8bf2efd7fde56c68a3f152a8 Author: Alexey Scherbakov Date: Sun Mar 10 20:58:57 2019 +0300 IGNITE-10078 Fixed mixed local and dht tx. commit 1e5796cfb4a8718d5d7fca3f7b050dbe99535615 Author: Alexey Scherbakov Date: Fri Mar 8 20:00:10 2019 +0300 IGNITE-10078 Cleaned up tests with all owners restart in the middle of tx. commit 29b87e76545f9a07b1ea53b01edd3e0f5bb9bf89 Author: Aleksei Scherbakov Date: Thu Mar 7 17:18:19 2019 +0300 IGNITE-10078 Added fail all test for history rebalance. commit 57ff05af9f00cc53ed829329e2b02e4e09c58b38 Author: Aleksei Scherbakov Date: Thu Mar 7 17:02:30 2019 +0300 IGNITE-10078 Cleaned up restart all on partial commit test. Property for failing nodes on counter inconsistency. commit 2b30ec1aaae0b6328a802d801af656ca700afc33 Merge: 8d39aab13b cfa12b19fa Author: Aleksei Scherbakov Date: Thu Mar 7 10:50:11 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 8d39aab13b8ac604ea30addd8cb9b13376699f2e Author: Aleksei Scherbakov Date: Tue Mar 5 13:17:52 2019 +0300 IGNITE-10078 Change counter generation for mvcc mode to not use reservation mode. commit 4a57bbdf6037df2c46f8f77cb67d3d42ad4dc76e Author: Aleksei Scherbakov Date: Mon Mar 4 19:48:23 2019 +0300 IGNITE-10078 Cleanup. commit 63ba1379e2edd8bc6f87b3116295326c4674dec3 Author: Aleksei Scherbakov Date: Mon Mar 4 17:23:05 2019 +0300 IGNITE-10078 Removed unneeded code. commit 0cd54d08722b12f9d25559c5f54d593a2434dbb0 Author: Aleksei Scherbakov Date: Mon Mar 4 17:19:11 2019 +0300 IGNITE-10078 Removed unneeded code. commit f21879a780f9320b4db4a75170473c84122bfee2 Merge: ed202a97cc 6008a0af5f Author: Aleksei Scherbakov Date: Mon Mar 4 16:12:52 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit ed202a97ccc7314ed0f7ab51285ebf2634a93e67 Author: Alexey Scherbakov Date: Sun Mar 3 21:44:20 2019 +0300 IGNITE-10078 wip. commit 91b5c27ff774e5eba799846fa570bf615c3a68c5 Merge: 949abb2e01 7100b05d96 Author: Alexey Scherbakov Date: Sun Mar 3 13:20:23 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 949abb2e01f6154adbd56458a3e5e29361a7ea07 Author: Aleksei Scherbakov Date: Thu Feb 28 20:37:53 2019 +0300 IGNITE-10078 removed commons-cli dep, uncommented mvcc tests. commit b416274f1d4bce8586e157d70d2515054b7efbd9 Author: Aleksei Scherbakov Date: Thu Feb 28 20:01:37 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/PartitionCountersNeighborcastFuture.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLocalTxStoreExceptionSelfTest.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite1.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite3.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite4.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite5.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite6.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite7.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite8.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite9.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java commit 4f9f9db63579129c3039a9c77c1982c95b25c3f9 Merge: 82869a6569 efc6b96578 Author: Aleksei Scherbakov Date: Thu Feb 28 19:36:44 2019 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/PartitionCountersNeighborcastFuture.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLocalTxStoreExceptionSelfTest.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite1.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite3.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite4.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite5.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite6.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite7.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite8.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite9.java # modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java commit 82869a65696545370aacb10ce053446694ec809c Author: Aleksei Scherbakov Date: Thu Feb 28 17:30:20 2019 +0300 IGNITE-10078 wip. commit a9a8f60163511a0bc150ee00cff05125b36eb670 Author: Aleksei Scherbakov Date: Thu Feb 28 17:27:08 2019 +0300 IGNITE-10078 debugging memleak. commit 86d1505501b25765cabf50f48b2793317aa181c7 Author: Aleksei Scherbakov Date: Thu Feb 28 13:39:32 2019 +0300 IGNITE-10078 debugging memleak. commit 63575fd7e028079058b38c924bbe5baa68663c54 Author: Alexey Scherbakov Date: Wed Feb 27 21:23:25 2019 +0300 IGNITE-10078 wip. commit fd39008ae713fd024ed2f9104865442a36af3144 Author: Aleksei Scherbakov Date: Wed Feb 27 19:03:49 2019 +0300 IGNITE-10078 debugging memleak. commit 9dc944768108dbef274b3e10268b2be701df53c9 Author: Aleksei Scherbakov Date: Wed Feb 27 18:58:19 2019 +0300 IGNITE-10078 debugging memleak. commit 5cc20becc77161e0f59a612721f928b909f609ee Author: Alexey Scherbakov Date: Wed Feb 27 09:28:12 2019 +0300 IGNITE-10078 wip. commit 08f4612f2224cbc7df1b947e54b6bcd153c88759 Author: Alexey Scherbakov Date: Wed Feb 27 00:51:29 2019 +0300 IGNITE-10078 wip. commit 9e8bf896ebbb9079441ab65092c42bd016b164e1 Author: Alexey Scherbakov Date: Mon Feb 25 22:52:46 2019 +0300 IGNITE-10078 wip. commit 8273eafe35b0f93c57cee20a4bd8a36de0434860 Author: Aleksei Scherbakov Date: Mon Feb 25 18:00:25 2019 +0300 IGNITE-10078 wip. commit 8288ba34a8e41a13ed92f66400aaa6fb29a0fcca Author: Alexey Scherbakov Date: Sun Feb 24 19:28:57 2019 +0300 IGNITE-10078 wip. commit 20d052268c27da3492e795cfeb38000921b7c83c Author: Aleksei Scherbakov Date: Wed Feb 20 19:30:08 2019 +0300 IGNITE-10078 wip. commit e48cd10c562d780ce54100be26611ace644fbaa6 Author: Alexey Scherbakov Date: Sun Feb 17 21:34:52 2019 +0300 IGNITE-10078 wip. commit 7f67efd960e2d5333cf0574f38d2154671c67e13 Author: Alexey Scherbakov Date: Sun Feb 17 18:30:44 2019 +0300 IGNITE-10078 wip. commit 9fa1128e22be21d88cd0e600232b7aa7148b7dca Author: Alexey Scherbakov Date: Sun Feb 17 18:18:32 2019 +0300 IGNITE-10078 wip. commit 9b6d2e67c2940579f95cd32b08cc0f75131f883d Author: Aleksei Scherbakov Date: Fri Feb 15 19:33:43 2019 +0300 IGNITE-10078 wip. commit 6ef3ddfe7291aa301090f5466ee44a7e1c475769 Author: Aleksei Scherbakov Date: Thu Feb 14 16:41:30 2019 +0300 IGNITE-10078 wip. commit aedadfbddae26807b3c8710c75bab3f7f5c52f1e Author: Aleksei Scherbakov Date: Tue Feb 12 16:00:26 2019 +0300 IGNITE-10078 wip. commit 5b46f2cd69ed32b12f6745eca46ace1940b82436 Author: Aleksei Scherbakov Date: Tue Feb 12 15:54:43 2019 +0300 IGNITE-10078 wip. commit 3d656cb3d7bcd7bd806c100ace10964585505376 Author: Aleksei Scherbakov Date: Mon Feb 11 15:58:09 2019 +0300 IGNITE-10078 wip. commit f3a9ae136df9c3867887e77da2630a7c88b74340 Author: Aleksei Scherbakov Date: Wed Jan 30 19:37:34 2019 +0300 IGNITE-10078 wip. commit 51b420a3493a39ed1cc890e423f61915a404b9a5 Author: Aleksei Scherbakov Date: Mon Jan 28 20:07:52 2019 +0300 IGNITE-10078 wip. commit d35ba43b4dc18cde5bfb5891b59dd55b38814529 Author: Aleksei Scherbakov Date: Fri Jan 25 19:35:43 2019 +0300 IGNITE-10078 wip. commit 2435f3855692c7e359f752ad6ff734fb3a3eb9c3 Author: Aleksei Scherbakov Date: Fri Jan 25 12:05:08 2019 +0300 IGNITE-10078 Implement read only counters to avoid unnecessary storage init. commit 1eab30f08e14bc0c6e519dbd9b1efe97173dd2f1 Author: Aleksei Scherbakov Date: Wed Jan 23 19:27:35 2019 +0300 IGNITE-10078 wip. commit e4ac96856ae975856acd5a67761ddd2ebc20ab56 Merge: b56a1b4422 15cefeabe1 Author: Aleksei Scherbakov Date: Wed Jan 23 19:27:22 2019 +0300 IGNITE-10078 wip. commit b56a1b442232358e1754e5ade92bbf4fc2e7ff22 Author: ascherbakoff Date: Sun Jan 20 20:33:03 2019 +0300 IGNITE-10078 wip. commit 1aaab90c9329910e906eeb3e01eb23381d77adde Author: ascherbakoff Date: Sun Jan 20 17:35:03 2019 +0300 IGNITE-10078 wip. commit 7bde03c5a98f229277a98bad76a3bcb95fcb0530 Author: Aleksei Scherbakov Date: Mon Jan 14 19:56:15 2019 +0300 IGNITE-10078 wip. commit e5da1e699595089b9a999ecde134a570ecc50637 Author: ascherbakoff Date: Sun Jan 13 21:30:03 2019 +0300 IGNITE-10078 wip. commit 18cb5c844aef1230892a42fc034a09546686f96d Author: ascherbakoff Date: Sun Jan 13 20:11:27 2019 +0300 IGNITE-10078 wip. commit f2b8509559118fb7ba4d1e9b7fc5d8c069b0e578 Author: Aleksei Scherbakov Date: Thu Jan 10 15:12:33 2019 +0300 IGNITE-10078 wip. commit 6858d29c24610c4d318ce698248ac98aa52034d9 Author: Aleksei Scherbakov Date: Wed Jan 9 20:11:53 2019 +0300 IGNITE-10078 wip. commit 06922c86c9d75a85780d3755dacb6a8ebb526c73 Author: Aleksei Scherbakov Date: Wed Jan 9 18:19:24 2019 +0300 IGNITE-10078 wip. commit bd658cdc017d56d0954b90966ccb6577753b7131 Author: Aleksei Scherbakov Date: Wed Jan 9 17:58:31 2019 +0300 IGNITE-10078 wip. commit a6841c4f59a76475b9fafcb75bc5552a0da5e117 Author: Aleksei Scherbakov Date: Wed Jan 9 17:41:11 2019 +0300 IGNITE-10078 wip. commit deb7c1a170c1ed7365523cb42c2c8781d2cf8a4e Author: ascherbakoff Date: Tue Jan 8 21:30:29 2019 +0300 IGNITE-10078 wip. commit 9375a0c1147b69cf3e5eb959248d9a101a89448e Author: ascherbakoff Date: Mon Jan 7 21:29:29 2019 +0300 IGNITE-10078 wip. commit dc25d341d50f4dbc49f0afa9f409732d48a96393 Author: ascherbakoff Date: Mon Jan 7 21:27:17 2019 +0300 IGNITE-10078 wip. commit 4aedc9f113e4b1ce81cc22b4812dc343022dd7e8 Author: ascherbakoff Date: Sat Jan 5 22:07:32 2019 +0300 IGNITE-10078 wip. commit 233fa73a5c2dc148433b1c4a62c73daf1643e175 Author: ascherbakoff Date: Sat Jan 5 22:07:18 2019 +0300 IGNITE-10078 wip. commit d349054573203b696f7194fd5d60d20c6136219e Author: ascherbakoff Date: Sat Jan 5 16:45:51 2019 +0300 IGNITE-10078 wip. commit b4ee593ae7a63b4c2384cca8be6445c402a2c88a Author: ascherbakoff Date: Fri Jan 4 20:32:57 2019 +0300 IGNITE-10078 wip. commit c0ac8df87163626e73b5b0a9cc7f9bb81ffefd62 Author: ascherbakoff Date: Fri Jan 4 20:30:52 2019 +0300 IGNITE-10078 wip. commit 6e31e7379e9597ace892b37c1e9db06be37369db Merge: 30393a15f6 bd6bc433bc Author: Aleksei Scherbakov Date: Fri Jan 4 20:20:59 2019 +0300 IGNITE-10078 wip. commit 30393a15f6e848096490ca50de75ab0ad7f60da8 Author: ascherbakoff Date: Fri Jan 4 19:57:04 2019 +0300 IGNITE-10078 wip. commit 78b976ba29a54322fb77978dd837d1235f9f956c Author: ascherbakoff Date: Fri Jan 4 19:55:34 2019 +0300 IGNITE-10078 wip. commit b71bb041e634da4f5498b483b6cf0b616a310f16 Author: ascherbakoff Date: Wed Jan 2 17:16:37 2019 +0300 IGNITE-10078 wip. commit 4e395780f2e930832ddb6af256bd9960ba34e56e Author: ascherbakoff Date: Fri Dec 28 16:59:46 2018 +0300 IGNITE-10078 wip. commit 7f57adc354054d8a176d6abdfa191472d86d23da Author: ascherbakoff Date: Fri Dec 28 13:26:28 2018 +0300 IGNITE-10078 wip. commit 78b7b21544ae18dffcbd28e11d870fb4e87e8968 Author: Aleksei Scherbakov Date: Thu Dec 27 19:04:07 2018 +0300 IGNITE-10078 wip. commit 458b9afdc28e318f6f1e2d84a482e6db56f89e0c Merge: 806f33ea32 ca71fe9ba1 Author: Aleksei Scherbakov Date: Thu Dec 27 19:03:22 2018 +0300 IGNITE-10078 wip. commit 806f33ea327669874bfc55a1c3ab8b2f336df05e Author: Aleksei Scherbakov Date: Thu Dec 27 18:23:46 2018 +0300 IGNITE-10078 wip. commit 0f4ea2945da15b8f05fd8c552ff49ff54bc49083 Author: Aleksei Scherbakov Date: Thu Dec 27 18:13:50 2018 +0300 IGNITE-10078 wip. commit f6408cb2335bc7a59237c38f405ea7fa18147ea1 Author: Aleksei Scherbakov Date: Thu Dec 27 17:33:41 2018 +0300 IGNITE-10078 wip. commit 804f15318e3c8843125b1c666559fea217df958b Author: Aleksei Scherbakov Date: Thu Dec 27 17:11:22 2018 +0300 IGNITE-10078 wip. commit bc90e89f9f02116cb481b18067f77cfb1b667333 Author: Aleksei Scherbakov Date: Thu Dec 27 17:06:57 2018 +0300 IGNITE-10078 wip. commit 70e055bc445e21ecade2674ff3f6afe0778e42f7 Author: Aleksei Scherbakov Date: Thu Dec 27 16:27:54 2018 +0300 IGNITE-10078 wip. commit 5c43d5b85676b9d2e9773aa660fc026b69b76746 Author: Aleksei Scherbakov Date: Thu Dec 27 15:50:08 2018 +0300 IGNITE-10078 wip. commit 77b244819fcd3d60089dcca1919e79a12ade1e2e Author: ascherbakoff Date: Wed Dec 26 23:18:06 2018 +0300 IGNITE-10078 wip. commit b7aadbe362ff10e12fa45366a95450eb6dfb5139 Author: Aleksei Scherbakov Date: Wed Dec 26 20:58:34 2018 +0300 IGNITE-10078 wip. commit 5d348022d338643c3fb083f98fe2a3f3e8dd9902 Author: Aleksei Scherbakov Date: Wed Dec 26 20:47:02 2018 +0300 IGNITE-10078 wip. commit 37056a266068007833ede53dddaad133a5ceda52 Author: Aleksei Scherbakov Date: Wed Dec 26 20:24:36 2018 +0300 IGNITE-10078 wip. commit a4f05d7c0fd2380694358d7e74ddb86ccc5dafec Author: Aleksei Scherbakov Date: Wed Dec 26 18:07:28 2018 +0300 IGNITE-10078 wip. commit ba12e3eea5eba72ad934b8ea9c29c7d9cd620be1 Author: Aleksei Scherbakov Date: Wed Dec 26 17:23:32 2018 +0300 IGNITE-10078 wip. commit 1c2fa92b3038b151e504d22884d53d54c590dc85 Author: Aleksei Scherbakov Date: Wed Dec 26 17:05:27 2018 +0300 IGNITE-10078 wip. commit 1f5f06922feaa8719e227df9b7258511e21ddcb8 Author: Aleksei Scherbakov Date: Wed Dec 26 13:38:29 2018 +0300 IGNITE-10078 wip. commit cad6c2bf2180c528486333f0dc4538b3b4f9ff13 Author: Aleksei Scherbakov Date: Wed Dec 26 11:45:58 2018 +0300 IGNITE-10078 wip. commit ba6332c328ea9fe30781e6a5cc1115380a71857b Author: Aleksei Scherbakov Date: Tue Dec 25 20:44:13 2018 +0300 IGNITE-10078 wip. commit 897a527e79bda8125c777d8fda9a595074c350eb Author: Aleksei Scherbakov Date: Tue Dec 25 20:40:17 2018 +0300 IGNITE-10078 wip. commit ef371035ba5ff530e74962846731ec7791aa20ec Author: Aleksei Scherbakov Date: Tue Dec 25 19:49:26 2018 +0300 IGNITE-10078 wip. commit 5b24857533ec3fa4b8f6e767cc148e964f5cfe07 Author: Aleksei Scherbakov Date: Tue Dec 25 19:46:40 2018 +0300 IGNITE-10078 wip. commit 158c1649562469257d7b32c7854d88cfbae46dcc Author: Aleksei Scherbakov Date: Tue Dec 25 17:15:54 2018 +0300 IGNITE-10078 wip. commit 1960c4b2e88069210fc2acbb8d49abe46c4328a7 Author: Aleksei Scherbakov Date: Tue Dec 25 17:03:40 2018 +0300 IGNITE-10078 wip. commit ecabcf35bc124ab66b4027096724a994d3cd6b56 Author: Aleksei Scherbakov Date: Tue Dec 25 11:56:50 2018 +0300 IGNITE-10078 wip. commit 0c3d2c9315b0577a878f94a8934f966ce25c6cc9 Author: Aleksei Scherbakov Date: Mon Dec 24 18:47:13 2018 +0300 IGNITE-10078 wip. commit d212202a3911dc0c6a99dbb1d67e437b5109452d Author: Aleksei Scherbakov Date: Mon Dec 24 18:42:06 2018 +0300 IGNITE-10078 wip. commit 987b344942483bd3e82f64f5bc47cba7f8cefb52 Author: Aleksei Scherbakov Date: Mon Dec 24 15:08:01 2018 +0300 IGNITE-10078 wip. commit 79dd016d0ac88ae770150033035533d205aac62b Author: Aleksei Scherbakov Date: Mon Dec 24 14:53:19 2018 +0300 IGNITE-10078 wip. commit dc110f0b8f56b72317b9446b4155529fc7dbf37d Author: ascherbakoff Date: Sun Dec 23 21:25:35 2018 +0300 IGNITE-10078 wip. commit 39f7e740216e95f4253c0796fa087ee69796748d Author: Aleksei Scherbakov Date: Fri Dec 21 20:50:42 2018 +0300 IGNITE-10078 wip. commit 2b668f0d20828c729c5a3536da806d4c43758792 Author: Aleksei Scherbakov Date: Fri Dec 21 20:49:19 2018 +0300 IGNITE-10078 wip. commit ef0da6871a45e313d63ed7c364ea0f21b071b72e Author: Aleksei Scherbakov Date: Fri Dec 21 20:48:53 2018 +0300 IGNITE-10078 wip. commit f213e4ed5d78202aeace9bb8629595709fa6874a Author: Aleksei Scherbakov Date: Fri Dec 21 19:11:01 2018 +0300 IGNITE-10078 wip. commit aaa280fa7016fb7ca63ae55d80c3857e11f09229 Author: Aleksei Scherbakov Date: Wed Dec 19 20:03:30 2018 +0300 IGNITE-10078 wip. commit 2ce83a2dcc9cde0428211f85d7eaa7eac5329368 Author: Aleksei Scherbakov Date: Wed Dec 19 14:30:35 2018 +0300 IGNITE-10078 wip. commit e1a19d5d830513a007266908bd24859cd0e79d9c Author: Aleksei Scherbakov Date: Tue Dec 18 18:53:57 2018 +0300 IGNITE-10078 wip. commit 56c48d55c555579abc28df3257d42a36806dbe80 Author: Aleksei Scherbakov Date: Tue Dec 18 18:38:22 2018 +0300 IGNITE-10078 wip. commit 8c58d38f3179645b7dc5e00f72212be5f32d3bfb Author: Aleksei Scherbakov Date: Tue Dec 18 17:56:27 2018 +0300 IGNITE-10078 wip. commit 8e19369343c50cc49826ee909d4a5bdff6de67a9 Author: Aleksei Scherbakov Date: Tue Dec 18 17:06:03 2018 +0300 IGNITE-10078 wip. commit 9d708ca48cdff7da4a4e04e3ef80807ae3d3005f Author: Aleksei Scherbakov Date: Tue Dec 18 14:34:38 2018 +0300 IGNITE-10078 wip. commit f3072e0288036c0543dade5909810f0600f669e2 Author: Aleksei Scherbakov Date: Tue Dec 18 14:14:52 2018 +0300 IGNITE-10078 Enable one-phase commit. commit c4b9664a3e6b6ab8229c1c714c16fb8c527e3eb0 Author: Aleksei Scherbakov Date: Tue Dec 18 14:12:08 2018 +0300 IGNITE-10078 wip. commit 161ebfa94f91469b1d945f75478661d3defc7831 Author: Aleksei Scherbakov Date: Mon Dec 17 19:54:15 2018 +0300 IGNITE-10078 wip. commit 737b0b31ffff42fd8e33a85ce7b1098f66eae57f Author: Aleksei Scherbakov Date: Mon Dec 17 19:43:02 2018 +0300 IGNITE-10078 wip. commit a7078dffdce93ce40411aa334cdb4c6282b168a4 Author: Aleksei Scherbakov Date: Mon Dec 17 18:02:09 2018 +0300 IGNITE-10078 wip. commit 3f9f79bb7460bbc56f5c6a428d4302e814060f25 Author: Aleksei Scherbakov Date: Mon Dec 17 13:43:38 2018 +0300 IGNITE-10078 wip. commit bdd8eb4ff0358a6359480449536ab6e18dd9d770 Author: Aleksei Scherbakov Date: Mon Dec 17 13:35:01 2018 +0300 IGNITE-10078 wip. commit 2916f2a33772fa9d6bf3cd24b8bab26848b7bfb5 Author: ascherbakoff Date: Sun Dec 16 16:17:50 2018 +0300 IGNITE-10078 wip. commit d3845bce883c741eea9058518e4cef5e6d0e64d9 Author: ascherbakoff Date: Sun Dec 16 15:20:24 2018 +0300 IGNITE-10078 wip. commit e7258b457f1b571b60bee063790cfbd2bb0d66c1 Author: Aleksei Scherbakov Date: Fri Dec 14 19:56:22 2018 +0300 IGNITE-10078 wip. commit 1fde3b63ea500b10d5aaf2ba7fc2faa047afb034 Author: Aleksei Scherbakov Date: Fri Dec 14 14:49:35 2018 +0300 IGNITE-10078 wip. commit f46ae88f3326b2f832e76b4e47a3fa2ad302b275 Author: Aleksei Scherbakov Date: Fri Dec 14 14:36:10 2018 +0300 IGNITE-10078 wip. commit 61b0c6d1c34a55b8e3c8d38ad6b2e33292809937 Author: Aleksei Scherbakov Date: Fri Dec 14 14:22:39 2018 +0300 IGNITE-10078 wip. commit 2debfa927c8f8b96dc8e31b19e7be1b131b26c5c Author: Aleksei Scherbakov Date: Fri Dec 14 13:41:06 2018 +0300 IGNITE-10078 wip. commit 909f2a349514ee42694b5b7a9cf1c559c16765b3 Author: Aleksei Scherbakov Date: Fri Dec 14 13:11:57 2018 +0300 IGNITE-10078 wip. commit 7877cb7ff8577ad5fac6361539fa56ef3c82c09b Author: Aleksei Scherbakov Date: Fri Dec 14 13:09:43 2018 +0300 IGNITE-10078 wip. commit 143339e0d8a985dea90bfe730f1941f3741bfe4b Author: Aleksei Scherbakov Date: Fri Dec 14 12:52:10 2018 +0300 IGNITE-10078 wip. commit 4280181b45cbb19aac66e2011786a299e6af5346 Author: Aleksei Scherbakov Date: Thu Dec 13 20:11:48 2018 +0300 IGNITE-10078 wip. commit 823eef29dcd530e5afce3f39ec2f74be41ea7b08 Author: Aleksei Scherbakov Date: Thu Dec 13 19:39:32 2018 +0300 IGNITE-10078 wip. commit 2a3ee55e26b2b556827bc32d4854c104343d2766 Author: Aleksei Scherbakov Date: Thu Dec 13 19:18:39 2018 +0300 IGNITE-10078 wip. commit 2976329006cd1d8b7cf5b2d6ae2ab9fe96a0e217 Author: Aleksei Scherbakov Date: Thu Dec 13 18:25:10 2018 +0300 IGNITE-10078 wip. commit fb92f91ece0e9749b4613a413022b4c447a49e89 Author: Aleksei Scherbakov Date: Thu Dec 13 18:11:13 2018 +0300 IGNITE-10078 wip. commit c02c54bfe64bf5daa33a31576b95a09128400e44 Author: Aleksei Scherbakov Date: Thu Dec 13 18:04:13 2018 +0300 IGNITE-10078 wip. commit 0ffdba5b270e2fa9c4a1aab475e13223868f2a7c Author: Aleksei Scherbakov Date: Thu Dec 13 16:28:54 2018 +0300 IGNITE-10078 wip. commit 9b9cb50a2e6d650b34a7df82cfc80837badbaae3 Author: Aleksei Scherbakov Date: Thu Dec 13 16:24:02 2018 +0300 IGNITE-10078 wip. commit 546275e360c200baf1987f06b5724abc67de8c33 Author: Aleksei Scherbakov Date: Thu Dec 13 16:15:17 2018 +0300 IGNITE-10078 wip. commit 9cf1280d47202a71e155fc400f5e09fc59313020 Merge: 96aabe9b7b 2bf085e877 Author: Aleksei Scherbakov Date: Thu Dec 13 14:14:03 2018 +0300 IGNITE-10078 wip. commit 96aabe9b7bdd6b04198ec958538b94085aa5739b Author: Aleksei Scherbakov Date: Thu Dec 13 13:54:59 2018 +0300 IGNITE-10078 wip. commit d3bbeddf6eeb02346c301dfa230795e7341de28a Author: Aleksei Scherbakov Date: Thu Dec 13 12:55:52 2018 +0300 IGNITE-10078 wip. commit bf7337235b8aedf05b195ecf1b39486b407eb426 Author: Aleksei Scherbakov Date: Wed Dec 12 20:22:12 2018 +0300 IGNITE-10078 wip. commit e624147bbe21b026079a2c4da22de06be0afd226 Author: Aleksei Scherbakov Date: Wed Dec 12 20:09:40 2018 +0300 IGNITE-10078 wip. commit 261ddd48dc4f408443f56b52df84d075765dc615 Author: Aleksei Scherbakov Date: Wed Dec 12 20:01:42 2018 +0300 IGNITE-10078 wip. commit 4e3c20e9012e83b34414ae9c3222347ba20febc7 Author: Aleksei Scherbakov Date: Wed Dec 12 19:57:09 2018 +0300 IGNITE-10078 wip. commit 17ae851b34c800c3986ce697da30bdc070206daf Author: Aleksei Scherbakov Date: Wed Dec 12 19:27:44 2018 +0300 IGNITE-10078 wip. commit 7016b30f0c42e369d713f18b4bffa101ac09626e Author: Aleksei Scherbakov Date: Wed Dec 12 19:22:25 2018 +0300 IGNITE-10078 wip. commit c53346f53f0bc5d8fabbb9e831eaa38725a85e62 Author: Aleksei Scherbakov Date: Wed Dec 12 18:51:16 2018 +0300 IGNITE-10078 wip. commit 6ed9fba3d42113046a9520ce4b910d645734a3f7 Author: Aleksei Scherbakov Date: Wed Dec 12 18:41:10 2018 +0300 IGNITE-10078 wip. commit 98ce00d16c4e73414a51a4ca9486d0e37969b556 Author: Aleksei Scherbakov Date: Wed Dec 12 14:52:17 2018 +0300 IGNITE-10078 wip. commit fe9719f7e16d35ffcfd448d2622c39e46bd01503 Author: Aleksei Scherbakov Date: Wed Dec 12 14:49:00 2018 +0300 IGNITE-10078 wip. commit db071ae2add8d687b1604aec42f1e683fc7608bc Author: Aleksei Scherbakov Date: Wed Dec 12 14:16:26 2018 +0300 IGNITE-10078 wip. commit 2206b0d117c9628a6e13c2785a9cc8cd4f44bcb3 Author: Aleksei Scherbakov Date: Wed Dec 12 14:06:28 2018 +0300 IGNITE-10078 wip. commit 67dd96faf96048b1f50bf529fc268f1115e09c68 Author: Aleksei Scherbakov Date: Tue Dec 11 19:27:33 2018 +0300 IGNITE-10078 wip. commit 3951f0baefab993882e2c8d8a1f916a23d89af85 Author: Aleksei Scherbakov Date: Tue Dec 11 19:24:45 2018 +0300 IGNITE-10078 wip. commit 8948804cebb8ff409ef4d700f0d52d589cb4bf16 Author: Aleksei Scherbakov Date: Tue Dec 11 18:53:41 2018 +0300 IGNITE-10078 wip. commit 4d182aa68b3b424390b04d7a1b8bcea79cd0070c Author: Aleksei Scherbakov Date: Tue Dec 11 18:50:35 2018 +0300 IGNITE-10078 wip. commit beb453b7b22aec136b6d79a0acd3cc7c7899d451 Author: Aleksei Scherbakov Date: Mon Dec 10 18:40:42 2018 +0300 IGNITE-10078 wip. commit dd05b00f0afbe0a2121091c8e20d10222c6b6f0a Author: Aleksei Scherbakov Date: Mon Dec 10 18:34:03 2018 +0300 IGNITE-10078 wip. commit 8d3842da5e130a361e52ace7b913933e6eb0d383 Author: Aleksei Scherbakov Date: Mon Dec 10 18:29:14 2018 +0300 IGNITE-10078 wip. commit 0b904406859e2851ec484022044255d32804e3bd Author: Aleksei Scherbakov Date: Mon Dec 10 18:25:15 2018 +0300 IGNITE-10078 wip. commit 7e3df8f06124745c8aedd9f5c32535c98840a1bb Merge: 1fc29dc2e0 87510597f5 Author: Aleksei Scherbakov Date: Mon Dec 10 18:20:33 2018 +0300 IGNITE-10078 wip. commit 1fc29dc2e0514aa20fd08dcf60536eded391faea Author: Aleksei Scherbakov Date: Mon Dec 10 17:06:42 2018 +0300 IGNITE-10078 wip. commit a84bd13a5aaeb203d84ef31f14fc967708c697f6 Merge: 26cbfe770b 4c48ae0ad2 Author: Aleksei Scherbakov Date: Mon Dec 10 17:04:25 2018 +0300 IGNITE-10078 wip. commit 26cbfe770b37bf7d0f946868cc191b37baf94ef8 Author: Aleksei Scherbakov Date: Mon Dec 10 16:51:43 2018 +0300 IGNITE-10078 wip. commit ada58ba6f146b6d556197fd658287173dc197629 Author: ascherbakoff Date: Sun Dec 9 21:25:26 2018 +0300 IGNITE-10078 wip. commit abb77c3d8167f6e3cbf5890cec8df9d930d802e1 Author: ascherbakoff Date: Sun Dec 9 20:22:31 2018 +0300 IGNITE-10078 wip. commit baab06840ac6ffeaf322be7ef0bedca6e6f90671 Author: Aleksei Scherbakov Date: Fri Dec 7 20:05:45 2018 +0300 IGNITE-10078 wip. commit 5ce148b0faa5415798a486b4d13fba8003d1623a Author: Aleksei Scherbakov Date: Thu Dec 6 18:47:35 2018 +0300 IGNITE-10078 wip. commit aec4bf2336338bc995993045e3bca194606980ee Author: Aleksei Scherbakov Date: Thu Dec 6 18:46:58 2018 +0300 IGNITE-10078 wip. commit d3827452dcd0ca23b35b71f619e9beb854943618 Author: Aleksei Scherbakov Date: Thu Dec 6 16:45:12 2018 +0300 IGNITE-10078 wip. commit ae248aae731c429d49b303a7c8dc3adf2cd53943 Author: Aleksei Scherbakov Date: Thu Dec 6 15:28:37 2018 +0300 IGNITE-10078 wip. commit 272e08e602a0b04d966c1800efc142f44d615797 Author: Aleksei Scherbakov Date: Thu Dec 6 14:27:21 2018 +0300 IGNITE-10078 wip. commit 3e747c8d12af9fed9851050c2dfa6d08439d68c0 Author: Aleksei Scherbakov Date: Thu Dec 6 13:44:13 2018 +0300 IGNITE-10078 wip. commit a0e6a1d329911d40f68c1cd4b93f9d586878dab0 Author: ascherbakoff Date: Wed Dec 5 23:25:06 2018 +0300 IGNITE-10078 wip. commit 0a0328ee8c4faa2af1d0c31913b12a02d1d3fef5 Author: Aleksei Scherbakov Date: Wed Dec 5 20:10:54 2018 +0300 IGNITE-10078 wip. commit 424855918b0f3c634b410fe4b90af0b3235a627a Author: Aleksei Scherbakov Date: Wed Dec 5 20:10:11 2018 +0300 IGNITE-10078 wip. commit 39770b9ff5b273e80084306f5173f7496e9c29b0 Author: Aleksei Scherbakov Date: Wed Dec 5 19:09:15 2018 +0300 IGNITE-10078 wip. commit 8cadd0666822420b1601f0acda3bf072296824a9 Author: Aleksei Scherbakov Date: Tue Dec 4 20:21:38 2018 +0300 IGNITE-10078 wip. commit 5446ac7ef00b9521da9c586d72fd3a42d6a722b7 Author: Aleksei Scherbakov Date: Tue Dec 4 20:10:41 2018 +0300 IGNITE-10078 wip. commit f45b1a5cefe332d538a1c505b9d1840d359da8a2 Author: Aleksei Scherbakov Date: Mon Dec 3 19:58:33 2018 +0300 IGNITE-10078 wip. commit 191cf44411a230099bbe0ff97c589d3a617bae18 Author: Aleksei Scherbakov Date: Mon Dec 3 19:55:52 2018 +0300 IGNITE-10078 wip. commit 68598271b519dc409680f86d5e303eaa24b91b3f Merge: 0448651174 826cc5573f Author: Aleksei Scherbakov Date: Mon Dec 3 10:59:15 2018 +0300 Merge branch 'ignite-10078' of https://github.com/gridgain/apache-ignite into ignite-10078 commit 826cc5573f42daefa4914beba9d37df6d5e8faf8 Author: ascherbakoff Date: Sun Dec 2 22:13:19 2018 +0300 IGNITE-10078 wip. commit 603930c315e3b1999de0313e8ad2a4114bfa8cbe Merge: 7a42fdbd82 2a0e354260 Author: ascherbakoff Date: Fri Nov 30 12:05:35 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 0448651174c41d33a10df44add94c25cd62d6b2d Merge: 7a42fdbd82 0e34042816 Author: Aleksei Scherbakov Date: Wed Nov 28 16:52:10 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 7a42fdbd821c2e57c3edff16cca719e17505b68d Author: Aleksei Scherbakov Date: Thu Nov 22 13:21:36 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java commit e9d52f94e9cb76f620bd9700aa1e7925f0a95842 Merge: a666157dc4 d81acdc29a Author: Aleksei Scherbakov Date: Thu Nov 22 13:14:10 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java commit a666157dc488c96fb5758daee24101c579e57b19 Author: Aleksei Scherbakov Date: Wed Nov 21 19:10:03 2018 +0300 IGNITE-10078 wip. commit 06aba801780def39cb00c23a3467a534f44b0b84 Author: ascherbakoff Date: Wed Nov 21 01:31:03 2018 +0300 IGNITE-10078 wip. commit 0b28c3d6da4285724116213d0b433160f62324cd Author: Aleksei Scherbakov Date: Mon Nov 19 17:05:32 2018 +0300 IGNITE-10078 wip. commit 29eee5c2c2790ff474957760973dd617a0584a61 Author: Aleksei Scherbakov Date: Mon Nov 19 17:02:32 2018 +0300 IGNITE-10078 wip. commit aacff35491a07f93ea844e360f774a0708b155c8 Merge: 97aba597a9 355ce6fe88 Author: Aleksei Scherbakov Date: Mon Nov 19 16:55:38 2018 +0300 IGNITE-10078 wip. commit 97aba597a95ea4dc5e2684dfb7bc68c23e3a98d0 Author: Aleksei Scherbakov Date: Mon Nov 19 16:49:39 2018 +0300 IGNITE-10078 wip. commit 30a8f30eef9d76d5aa72f2bc43882c7e47f5d221 Author: Aleksei Scherbakov Date: Mon Nov 19 16:20:16 2018 +0300 IGNITE-10078 wip. commit d176c8b30c303f19b5beeff640e7ed5b961f81c3 Author: Aleksei Scherbakov Date: Mon Nov 19 13:34:39 2018 +0300 IGNITE-10078 wip. commit 22436a83dc0993461c08155b9e68b612dda3360a Author: ascherbakoff Date: Sun Nov 18 18:37:16 2018 +0300 IGNITE-10078 wip. commit ef7a7857fc00bebe9fc9289ecdb687c43973e947 Author: ascherbakoff Date: Sun Nov 18 17:43:15 2018 +0300 IGNITE-10078 wip. commit e721aba13512433caf9b6420e00dfef76dce3c47 Author: ascherbakoff Date: Sun Nov 18 17:31:20 2018 +0300 IGNITE-10078 wip. commit 2efba0a10b64490ac435e0157a5eeca8c2712ecc Author: ascherbakoff Date: Sun Nov 18 17:12:14 2018 +0300 IGNITE-10078 wip. commit e210e1cb26e774625252b1a2f11d295f80f48351 Author: ascherbakoff Date: Sun Nov 18 17:06:45 2018 +0300 IGNITE-10078 wip. commit 63d7ab771d664eafc1e5f18f7a2f51500113316b Author: Aleksei Scherbakov Date: Fri Nov 16 18:51:59 2018 +0300 IGNITE-10078 wip. commit 2317758268879c647d80367f44c121645713de78 Author: Aleksei Scherbakov Date: Wed Nov 14 17:45:49 2018 +0300 IGNITE-10078 wip. commit 64d7e2d2a235fb822b68ca21f02d85f43f88b019 Merge: defbcc167a 2439ade4d6 Author: ascherbakoff Date: Mon Nov 12 22:42:43 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit defbcc167aaf358991c2874b2b0d600b6248f921 Author: ascherbakoff Date: Mon Nov 12 22:41:57 2018 +0300 IGNITE-10078 wip. commit a43e5876cb81bb00fdbccc004d28e9c4ceda475a Author: Aleksei Scherbakov Date: Tue Nov 6 10:31:38 2018 +0300 IGNITE-10078 wip. commit beb579c83782ef4d2be91a29c43b99410e4f8d6d Merge: 253df1059b 6f9c702cd7 Author: Aleksei Scherbakov Date: Thu Nov 1 12:51:24 2018 +0300 Merge branch 'master' of https://github.com/apache/ignite into ignite-10078 commit 253df1059b0ad0f003a711e63007df7b2e1b77c0 Author: Aleksei Scherbakov Date: Wed Oct 31 18:38:07 2018 +0300 IGNITE-10078 wip. Signed-off-by: Anton Vinogradov --- .../org/apache/ignite/IgniteSystemProperties.java | 7 + .../src/main/java/org/apache/ignite/Ignition.java | 2 +- .../apache/ignite/internal/pagemem/FullPageId.java | 6 +- .../pagemem/wal/record/RollbackRecord.java | 115 +++ .../internal/pagemem/wal/record/WALRecord.java | 8 +- .../delta/MetaPageUpdatePartitionDataRecord.java | 38 +- .../delta/MetaPageUpdatePartitionDataRecordV2.java | 103 ++ .../wal/record/delta/PartitionMetaStateRecord.java | 8 +- .../processors/affinity/AffinityAssignment.java | 2 +- .../affinity/GridAffinityAssignmentCache.java | 14 +- .../cache/CacheAffinitySharedManager.java | 334 ++---- .../processors/cache/CacheEntryInfoCollection.java | 19 + .../processors/cache/CacheGroupContext.java | 13 + .../processors/cache/GridCacheMapEntry.java | 51 +- .../cache/GridCachePartitionExchangeManager.java | 10 +- .../processors/cache/GridCacheProcessor.java | 32 +- .../cache/GridCacheSharedTtlCleanupManager.java | 9 +- .../internal/processors/cache/GridCacheUtils.java | 3 +- .../cache/IgniteCacheOffheapManager.java | 61 +- .../cache/IgniteCacheOffheapManagerImpl.java | 94 +- .../cache/PartitionAtomicUpdateCounterImpl.java | 155 +++ ....java => PartitionMvccTxUpdateCounterImpl.java} | 41 +- .../PartitionTxUpdateCounterDebugWrapper.java | 201 ++++ .../cache/PartitionTxUpdateCounterImpl.java | 450 ++++++++ .../processors/cache/PartitionUpdateCounter.java | 223 ++-- .../internal/processors/cache/WalStateManager.java | 10 +- .../GridDistributedTxRemoteAdapter.java | 3 +- .../cache/distributed/dht/GridDhtCacheEntry.java | 28 +- .../distributed/dht/GridDhtTxFinishFuture.java | 9 +- .../distributed/dht/GridDhtTxFinishRequest.java | 7 - .../distributed/dht/GridDhtTxPrepareFuture.java | 35 +- .../dht/PartitionUpdateCountersMessage.java | 24 + .../dht/preloader/GridDhtPartitionDemander.java | 6 +- .../dht/preloader/GridDhtPartitionSupplier.java | 9 + .../preloader/GridDhtPartitionsExchangeFuture.java | 75 +- .../dht/preloader/GridDhtPreloader.java | 8 +- .../dht/preloader/GridDhtPreloaderAssignments.java | 3 +- .../preloader/IgniteDhtDemandedPartitionsMap.java | 3 + .../dht/topology/GridClientPartitionTopology.java | 7 +- .../dht/topology/GridDhtLocalPartition.java | 121 ++- .../dht/topology/GridDhtPartitionTopology.java | 12 +- .../dht/topology/GridDhtPartitionTopologyImpl.java | 120 ++- .../dht/topology/PartitionsEvictManager.java | 52 +- .../GridNearOptimisticTxPrepareFutureAdapter.java | 6 +- .../cache/distributed/near/GridNearTxLocal.java | 15 +- .../processors/cache/persistence/CacheDataRow.java | 8 + .../cache/persistence/CacheDataRowAdapter.java | 2 +- .../GridCacheDatabaseSharedManager.java | 78 +- .../cache/persistence/GridCacheOffheapManager.java | 365 +++++-- .../processors/cache/persistence/RowStore.java | 6 + .../processors/cache/persistence/Storable.java | 7 + .../persistence/checkpoint/CheckpointEntry.java | 3 +- .../persistence/freelist/AbstractFreeList.java | 37 +- .../persistence/freelist/CacheFreeListImpl.java | 10 +- .../cache/persistence/freelist/PagesList.java | 14 +- .../SimpleDataRow.java} | 82 +- .../cache/persistence/metastorage/MetaStorage.java | 133 +-- .../metastorage/MetastorageDataRow.java | 64 +- .../metastorage/MetastorageRowStore.java | 32 +- .../MetastoreDataPageIO.java} | 39 +- .../PartitionMetaStorage.java} | 33 +- .../partstorage/PartitionMetaStorageImpl.java | 140 +++ .../cache/persistence/tree/BPlusTree.java | 1 + .../persistence/tree/io/AbstractDataPageIO.java | 1 - .../cache/persistence/tree/io/PageIO.java | 7 + .../persistence/tree/io/PagePartitionMetaIO.java | 34 + .../persistence/tree/io/PagePartitionMetaIOV2.java | 51 +- .../persistence/tree/io/SimpleDataPageIO.java | 35 +- .../cache/persistence/tree/util/PageHandler.java | 3 +- .../persistence/wal/FileWriteAheadLogManager.java | 19 +- .../cache/persistence/wal/record/RecordTypes.java | 1 + .../wal/serializer/RecordDataV1Serializer.java | 37 +- .../wal/serializer/RecordDataV2Serializer.java | 22 + .../CacheContinuousQueryEventBuffer.java | 14 +- .../continuous/CacheContinuousQueryHandler.java | 6 +- .../cache/transactions/IgniteTxEntry.java | 19 + .../cache/transactions/IgniteTxHandler.java | 88 +- .../cache/transactions/IgniteTxLocalAdapter.java | 34 +- .../cache/transactions/IgniteTxManager.java | 4 +- .../processors/cache/transactions/TxCounters.java | 25 +- .../cluster/GridClusterStateProcessor.java | 3 +- .../ignite/internal/stat/IoStatisticsHolder.java | 1 - .../apache/ignite/internal/util/IgniteTree.java | 5 +- .../apache/ignite/internal/util/IgniteUtils.java | 62 +- modules/core/src/test/config/log4j-test.xml | 9 + .../ignite/cache/ResetLostPartitionTest.java | 5 +- .../internal/TestRecordingCommunicationSpi.java | 55 +- .../processors/cache/IgniteCacheGroupsTest.java | 16 +- .../CachePartitionLossDetectionOnNodeLeftTest.java | 115 +++ .../distributed/CacheRentingStateRepairTest.java | 25 +- .../GridCacheRebalancingWithAsyncClearingTest.java | 12 +- .../IgnitePdsCacheRebalancingAbstractTest.java | 4 + .../IgnitePdsContinuousRestartTest.java | 10 + ...tePdsContinuousRestartTestWithExpiryPolicy.java | 1 + .../persistence/IgnitePdsCorruptedStoreTest.java | 40 +- .../db/IgnitePdsPartitionPreloadTest.java | 19 +- .../persistence/db/wal/IgniteWalRebalanceTest.java | 2 +- .../db/wal/IgniteWalSerializerVersionTest.java | 2 +- .../db/wal/WalRecoveryTxLogicalRecordsTest.java | 162 ++- .../transactions/PartitionUpdateCounterTest.java | 425 ++++++++ .../TxLocalDhtMixedCacheModesTest.java | 86 ++ .../TxPartitionCounterStateAbstractTest.java | 1081 ++++++++++++++++++++ ...ounterStateConsistencyHistoryRebalanceTest.java | 191 ++++ .../TxPartitionCounterStateConsistencyTest.java | 490 +++++++++ ...ateOnePrimaryOneBackupHistoryRebalanceTest.java | 41 + ...rtitionCounterStateOnePrimaryOneBackupTest.java | 491 +++++++++ ...imaryTwoBackupsFailAllHistoryRebalanceTest.java | 100 ++ ...ounterStateOnePrimaryTwoBackupsFailAllTest.java | 352 +++++++ ...teOnePrimaryTwoBackupsHistoryRebalanceTest.java | 64 ++ ...titionCounterStateOnePrimaryTwoBackupsTest.java | 913 +++++++++++++++++ .../TxPartitionCounterStatePutTest.java | 289 ++++++ ...titionCounterStateTwoPrimaryTwoBackupsTest.java | 225 ++++ .../TxPartitionCounterStateWithFilterTest.java | 200 ++++ .../cache/transactions/TxRollbackAsyncTest.java | 2 +- .../testframework/junits/GridAbstractTest.java | 3 + .../ignite/testframework/junits/Repeat.java} | 51 +- .../ignite/testframework/junits/RepeatRule.java | 67 ++ .../junits/common/GridCommonAbstractTest.java | 196 +++- .../testsuites/IgniteCacheMvccTestSuite6.java | 4 + .../testsuites/IgniteCacheMvccTestSuite9.java | 22 + .../ignite/testsuites/IgniteCacheTestSuite6.java | 6 + .../ignite/testsuites/IgniteCacheTestSuite9.java | 24 + .../processors/cache/CacheIndexStreamerTest.java | 3 + 123 files changed, 8591 insertions(+), 1289 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index 800ca56..a8916b8 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -1145,6 +1145,13 @@ public final class IgniteSystemProperties { public static final String IGNITE_DIAGNOSTIC_WARN_LIMIT = "IGNITE_DIAGNOSTIC_WARN_LIMIT"; /** + * Flag to enable triggering failure handler for node if unrecoverable partition inconsistency is + * discovered during partition update counters exchange. + */ + public static final String IGNITE_FAIL_NODE_ON_UNRECOVERABLE_PARTITION_INCONSISTENCY = + "IGNITE_FAIL_NODE_ON_UNRECOVERABLE_PARTITION_INCONSISTENCY"; + + /** * Allow use composite _key, _val columns at the INSERT/UPDATE/MERGE statements. */ public static final String IGNITE_SQL_ALLOW_KEY_VAL_UPDATES = "IGNITE_SQL_ALLOW_KEY_VAL_UPDATES"; diff --git a/modules/core/src/main/java/org/apache/ignite/Ignition.java b/modules/core/src/main/java/org/apache/ignite/Ignition.java index 4c7a491..dd0d796 100644 --- a/modules/core/src/main/java/org/apache/ignite/Ignition.java +++ b/modules/core/src/main/java/org/apache/ignite/Ignition.java @@ -583,4 +583,4 @@ public class Ignition { return TcpIgniteClient.start(cfg); } -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java index 9e24943..17c552d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java @@ -40,10 +40,10 @@ import org.apache.ignite.internal.util.typedef.internal.U; *

*

Page ID rotation

* There are scenarios when we reference one page (B) from within another page (A) by page ID. It is also - * possible that this first page (B) is de-allocated and allocated again for a different purpose. In this - * case we should have a mechanism to determine that page (B) cannot be used after reading it's ID in page (A). + * possible that this first page (B) is concurrently reused for a different purpose. In this + * case we should have a mechanism to determine that the reference from page (A) to page (B) is no longer valid. * This is ensured by page ID rotation - together with page's (B) ID we should write some value that is incremented - * each time a page is de-allocated (page ID rotation). This ID should be verified after page read and a page + * each time a page is reused (page ID rotation). This ID should be verified after page read and a page * should be discarded if full ID is different. *

* Effective page ID is page ID with zeroed bits used for page ID rotation. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/RollbackRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/RollbackRecord.java new file mode 100644 index 0000000..fd6a00e --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/RollbackRecord.java @@ -0,0 +1,115 @@ +/* + * 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.pagemem.wal.record; + +import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * Rollback record. Used to close gap in partition update sequence on tx rollback. + */ +public class RollbackRecord extends WALRecord { + /** Cache ID. */ + @GridToStringInclude + protected int grpId; + + /** Partition ID. */ + @GridToStringInclude + protected int partId; + + /** Rollback start. */ + @GridToStringInclude + protected long start; + + /** Rollback range. */ + @GridToStringInclude + protected long range; + + /** + * @param grpId Group id. + * @param partId Partition id. + * @param start Start. + * @param range Range. + */ + public RollbackRecord(int grpId, int partId, long start, long range) { + this.grpId = grpId; + this.partId = partId; + this.start = start; + this.range = range; + } + + /** + * @return Cache ID. + */ + public int groupId() { + return grpId; + } + + /** + * @return Partition ID. + */ + public int partitionId() { + return partId; + } + + /** + * @return Rollback start. + */ + public long start() { + return start; + } + + /** + * @return Rollback range. + */ + public long range() { + return range; + } + + /** + * Returns a number of overlapping update counters. + * + * @param from From counter (not inclusive). + * @param to To counter (inclusive). + */ + public long overlap(long from, long to) { + long to0 = start + range; + + // from lies within (start, to0] + if (start <= from && from < to0) + return Math.min(to0 - from, to - from); + + // start lies within (from, to] + if (from <= start && start < to) + return Math.min(to - start, range); + + return 0; + } + + + + /** {@inheritDoc} */ + @Override public RecordType type() { + return RecordType.ROLLBACK_TX_RECORD; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(RollbackRecord.class, this); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java index 5d72768..9cf2613 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java @@ -208,7 +208,13 @@ public abstract class WALRecord { MVCC_DATA_RECORD (LOGICAL), /** Mvcc Tx state change record. */ - MVCC_TX_RECORD (LOGICAL); + MVCC_TX_RECORD (LOGICAL), + + /** Rollback tx record. */ + ROLLBACK_TX_RECORD (LOGICAL), + + /** */ + PARTITION_META_PAGE_UPDATE_COUNTERS_V2 (PHYSICAL); /** * When you're adding a new record don't forget to choose record purpose explicitly diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecord.java index 28294a9..3e2b67b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecord.java @@ -17,7 +17,11 @@ package org.apache.ignite.internal.pagemem.wal.record.delta; +import java.io.DataInput; +import java.io.IOException; +import java.nio.ByteBuffer; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionMetaIO; import org.apache.ignite.internal.util.typedef.internal.S; @@ -57,8 +61,7 @@ public class MetaPageUpdatePartitionDataRecord extends PageDeltaRecord { int partSize, long cntrsPageId, byte state, - int allocatedIdxCandidate - ) { + int allocatedIdxCandidate) { super(grpId, pageId); this.updateCntr = updateCntr; @@ -70,6 +73,20 @@ public class MetaPageUpdatePartitionDataRecord extends PageDeltaRecord { } /** + * @param in Input. + */ + public MetaPageUpdatePartitionDataRecord(DataInput in) throws IOException{ + super(in.readInt(), in.readLong()); + + this.updateCntr = in.readLong(); + this.globalRmvId = in.readLong(); + this.partSize = in.readInt(); + this.cntrsPageId = in.readLong(); + this.state = in.readByte(); + this.allocatedIdxCandidate = in.readInt(); + } + + /** * @return Update counter. */ public long updateCounter() { @@ -123,6 +140,21 @@ public class MetaPageUpdatePartitionDataRecord extends PageDeltaRecord { return allocatedIdxCandidate; } + /** + * @param buf Buffer. + */ + public void toBytes(ByteBuffer buf) { + buf.putInt(groupId()); + buf.putLong(pageId()); + + buf.putLong(updateCounter()); + buf.putLong(globalRemoveId()); + buf.putInt(partitionSize()); + buf.putLong(countersPageId()); + buf.put(state()); + buf.putInt(allocatedIndexCandidate()); + } + /** {@inheritDoc} */ @Override public RecordType type() { return RecordType.PARTITION_META_PAGE_UPDATE_COUNTERS; @@ -130,6 +162,6 @@ public class MetaPageUpdatePartitionDataRecord extends PageDeltaRecord { /** {@inheritDoc} */ @Override public String toString() { - return S.toString(MetaPageUpdatePartitionDataRecord.class, this, "super", super.toString()); + return S.toString(MetaPageUpdatePartitionDataRecord.class, this, "partId", PageIdUtils.partId(pageId()), "super", super.toString()); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecordV2.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecordV2.java new file mode 100644 index 0000000..ab3ccf8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageUpdatePartitionDataRecordV2.java @@ -0,0 +1,103 @@ +/* + * 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.pagemem.wal.record.delta; + +import java.io.DataInput; +import java.io.IOException; +import java.nio.ByteBuffer; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageIdUtils; +import org.apache.ignite.internal.pagemem.PageMemory; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionMetaIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionMetaIOV2; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * + */ +public class MetaPageUpdatePartitionDataRecordV2 extends MetaPageUpdatePartitionDataRecord { + /** */ + private long link; + + /** + * @param grpId Group id. + * @param pageId Page id. + * @param updateCntr Update counter. + * @param globalRmvId Global remove id. + * @param partSize Partition size. + * @param cntrsPageId Cntrs page id. + * @param state State. + * @param allocatedIdxCandidate Allocated index candidate. + * @param link Link. + */ + public MetaPageUpdatePartitionDataRecordV2( + int grpId, + long pageId, + long updateCntr, + long globalRmvId, + int partSize, + long cntrsPageId, + byte state, + int allocatedIdxCandidate, + long link) { + super(grpId, pageId, updateCntr, globalRmvId, partSize, cntrsPageId, state, allocatedIdxCandidate); + this.link = link; + } + + /** + * @param in Input. + */ + public MetaPageUpdatePartitionDataRecordV2(DataInput in) throws IOException { + super(in); + + this.link = in.readLong(); + } + + /** {@inheritDoc} */ + @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { + super.applyDelta(pageMem, pageAddr); + + PagePartitionMetaIOV2 io = (PagePartitionMetaIOV2)PagePartitionMetaIO.VERSIONS.forPage(pageAddr); + + io.setGapsLink(pageAddr, link); + } + + /** + * + */ + public long link() { + return link; + } + + /** {@inheritDoc} */ + @Override public void toBytes(ByteBuffer buf) { + super.toBytes(buf); + + buf.putLong(link()); + } + + /** {@inheritDoc} */ + @Override public RecordType type() { + return RecordType.PARTITION_META_PAGE_UPDATE_COUNTERS_V2; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(MetaPageUpdatePartitionDataRecordV2.class, this, "partId", PageIdUtils.partId(pageId()), "super", super.toString()); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PartitionMetaStateRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PartitionMetaStateRecord.java index e1e74c4..399ffc2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PartitionMetaStateRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PartitionMetaStateRecord.java @@ -35,12 +35,14 @@ public class PartitionMetaStateRecord extends WALRecord implements WalRecordCach /** Partition id. */ private final int partId; - /** Update counter. */ + /** @deprecated Update counter. */ private final long updateCounter; /** * @param grpId Cache group ID. - * @param state Page ID. + * @param partId Partition ID. + * @param state State. + * @param updateCounter Update counter. */ public PartitionMetaStateRecord(int grpId, int partId, GridDhtPartitionState state, long updateCounter) { this.grpId = grpId; @@ -74,7 +76,7 @@ public class PartitionMetaStateRecord extends WALRecord implements WalRecordCach } /** - * + * @return Rollback counter. */ public long updateCounter() { return updateCounter; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityAssignment.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityAssignment.java index b8b1089..502672c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityAssignment.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityAssignment.java @@ -74,7 +74,7 @@ public interface AffinityAssignment { public Collection getIds(int part); /** - * @return Nodes having parimary and backup assignments. + * @return Nodes having primary and backup assignments. */ public Set nodes(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java index 7c2b1dc..53664b8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java @@ -352,22 +352,22 @@ public class GridAffinityAssignmentCache { if (hasBaseline && changedBaseline) { recalculateBaselineAssignment(topVer, events, prevAssignment, sorted, blt); - assignment = IdealAffinityAssignment.createWithPreservedPrimaries( + assignment = IdealAffinityAssignment.create( topVer, - baselineAssignmentWithoutOfflineNodes(topVer), - baselineAssignment + sorted, + baselineAssignmentWithoutOfflineNodes(topVer) ); } else if (skipCalculation) assignment = prevAssignment; - else if (hasBaseline && !changedBaseline) { + else if (hasBaseline) { if (baselineAssignment == null) recalculateBaselineAssignment(topVer, events, prevAssignment, sorted, blt); - assignment = IdealAffinityAssignment.createWithPreservedPrimaries( + assignment = IdealAffinityAssignment.create( topVer, - baselineAssignmentWithoutOfflineNodes(topVer), - baselineAssignment + sorted, + baselineAssignmentWithoutOfflineNodes(topVer) ); } else { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java index 9a80d8a..7bdb602 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java @@ -269,7 +269,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap CacheAffinityChangeMessage msg = null; synchronized (mux) { - if (waitInfo == null || !waitInfo.topVer.equals(lastAffVer) ) + if (waitInfo == null || !waitInfo.topVer.equals(lastAffVer)) return; Map partWait = waitInfo.waitGrps.get(checkGrpId); @@ -324,7 +324,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap */ public Set waitGroups() { synchronized (mux) { - if (waitInfo == null || !waitInfo.topVer.equals(lastAffVer) ) + if (waitInfo == null || !waitInfo.topVer.equals(lastAffVer)) return Collections.emptySet(); return new HashSet<>(waitInfo.waitGrps.keySet()); @@ -332,6 +332,21 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap } /** + * @param grpId Group id. + * @param part Part. + * @param node Node. + * @param topVer Topology version. + */ + public void addToWaitGroup(int grpId, int part, UUID node, AffinityTopologyVersion topVer) { + synchronized (mux) { + if (waitInfo == null) + waitInfo = new WaitRebalanceInfo(topVer); + + waitInfo.add(grpId, part, node, null); + } + } + + /** * @param waitInfo Cache rebalance information. * @return Message. */ @@ -495,6 +510,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap clientTop.fullUpdateCounters(), Collections.emptySet(), null, + null, null ); } @@ -560,7 +576,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap -1, false); - grp.topology().update(topVer, partMap, null, Collections.emptySet(), null, null); + grp.topology().update(topVer, partMap, null, Collections.emptySet(), null, null, null); topFut.validate(grp, discoCache.allNodes()); } @@ -791,8 +807,8 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap } /** - * Called during the rollback of the exchange partitions procedure - * in order to stop the given cache even if it's not fully initialized (e.g. failed on cache init stage). + * Called during the rollback of the exchange partitions procedure in order to stop the given cache even if it's not + * fully initialized (e.g. failed on cache init stage). * * @param fut Exchange future. * @param crd Coordinator flag. @@ -803,7 +819,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap boolean crd, final ExchangeActions exchActions ) { - assert exchActions != null && !exchActions.empty() && exchActions.cacheStartRequests().isEmpty(): exchActions; + assert exchActions != null && !exchActions.empty() && exchActions.cacheStartRequests().isEmpty() : exchActions; IgniteInternalFuture res = cachesRegistry.update(exchActions); @@ -1613,182 +1629,15 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @throws IgniteCheckedException If failed. */ public Map onServerLeftWithExchangeMergeProtocol( - final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException - { - final ExchangeDiscoveryEvents evts = fut.context().events(); - - assert fut.context().mergeExchanges(); - assert evts.hasServerLeft(); - - if (evts.hasServerLeft() && evts.hasServerJoin()) - return onReassignmentEnforced(fut); - else - return onServerLeftWithExchangeMergeProtocolLightweight(fut); - } - - /** - * @param fut Current exchange future. - * @return Computed difference with ideal affinity. - * @throws IgniteCheckedException If failed. - */ - private Map onServerLeftWithExchangeMergeProtocolLightweight( - final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException - { + final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException { final ExchangeDiscoveryEvents evts = fut.context().events(); - final AffinityTopologyVersion topVer = evts.topologyVersion(); assert fut.context().mergeExchanges(); assert evts.hasServerLeft(); - final WaitRebalanceInfo waitRebalanceInfo = - new WaitRebalanceInfo(fut.context().events().lastServerEventVersion()); - - final Map>> diff = new ConcurrentHashMap<>(); - - final Set aliveNodes = new HashSet<>(fut.context().events().discoveryCache().serverNodes()); - - forAllRegisteredCacheGroups(new IgniteInClosureX() { - @Override public void applyx(CacheGroupDescriptor desc) throws IgniteCheckedException { - AffinityTopologyVersion topVer = evts.topologyVersion(); - - CacheGroupHolder grpHolder = getOrCreateGroupHolder(topVer, desc); - - IdealAffinityAssignment idealAssignment = grpHolder.affinity().calculate(topVer, evts, evts.discoveryCache()); - - if (!grpHolder.rebalanceEnabled || fut.cacheGroupAddedOnExchange(desc.groupId(), desc.receivedFrom())) { - grpHolder.affinity().initialize(topVer, idealAssignment.assignment()); - - return; - } - - AffinityTopologyVersion affTopVer = grpHolder.affinity().lastVersion(); - - List> curAssignment = grpHolder.affinity().assignments(affTopVer); - - assert curAssignment != null; - - List> newAssignment = new ArrayList<>(idealAssignment.assignment()); - - GridDhtPartitionTopology top = grpHolder.topology(fut.context().events().discoveryCache()); - - BitSet processedPartitions = new BitSet(curAssignment.size()); - - Map> cacheAffinityDiff = new HashMap<>(); - - for (ClusterNode leftNode : evts.leftServerNodes()) { - for (int p : idealAssignment.idealPrimaries(leftNode)) { - List curOwners = curAssignment.get(p); - - if (curOwners.isEmpty()) - continue; - - List idealOwners = idealAssignment.assignment().get(p); - - List newOwners = null; - - if (idealOwners.isEmpty()) - newOwners = selectCurrentAliveOwners(aliveNodes, curOwners); - else if (curOwners.get(0).equals(leftNode)) - newOwners = selectPrimaryTopologyOwnerFromIdealAssignment( - grpHolder.aff, - p, - top, - idealOwners, - waitRebalanceInfo - ); - else if (!curOwners.get(0).equals(idealOwners.get(0))) - newOwners = latePrimaryAssignment( - grpHolder.aff, - p, - curOwners.get(0), - idealOwners, - waitRebalanceInfo - ); - - if (newOwners != null) { - newAssignment.set(p, newOwners); - - List clusterNodesAsOrder = newOwners.stream() - .map(NODE_TO_ORDER::apply) - .collect(Collectors.toList()); - - cacheAffinityDiff.put(p, clusterNodesAsOrder); - - processedPartitions.set(p); - } - } - } - - Set partitionsWithChangedPrimary = grpHolder.affinity().partitionPrimariesDifferentToIdeal(affTopVer); - - // We need to re-check partitions for further correct late affinity assignment - // where primary node is not as in ideal assignment. - for (int p : partitionsWithChangedPrimary) { - if (processedPartitions.get(p)) - continue; - - List curOwners = curAssignment.get(p); - - if (curOwners.isEmpty()) - continue; - - List idealOwners = idealAssignment.assignment().get(p); - - List newOwners = null; - - if (idealOwners.isEmpty()) - newOwners = selectCurrentAliveOwners(aliveNodes, curOwners); - else if (!aliveNodes.contains(curOwners.get(0))) - newOwners = selectPrimaryTopologyOwnerFromIdealAssignment( - grpHolder.aff, - p, - top, - idealOwners, - waitRebalanceInfo - ); - else if (!curOwners.get(0).equals(idealOwners.get(0))) - // Current distribution was already not ideal. Preserve it for late affinity assignment. - newOwners = latePrimaryAssignment( - grpHolder.aff, - p, - curOwners.get(0), - idealOwners, - waitRebalanceInfo - ); - - if (newOwners != null) { - newAssignment.set(p, newOwners); - - List clusterNodesAsOrder = newOwners.stream() - .map(NODE_TO_ORDER::apply) - .collect(Collectors.toList()); - - cacheAffinityDiff.put(p, clusterNodesAsOrder); - } - } - - if (!cacheAffinityDiff.isEmpty()) - diff.put(grpHolder.groupId(), cacheAffinityDiff); - - grpHolder.affinity().initialize(topVer, newAssignment); - - fut.timeBag().finishLocalStage("Affinity initialization (on server left) " + - "[grp=" + desc.cacheOrGroupName() + "]"); - } - }); - - synchronized (mux) { - this.waitInfo = !waitRebalanceInfo.empty() ? waitRebalanceInfo : null; - - WaitRebalanceInfo info = this.waitInfo; - - if (log.isDebugEnabled()) { - log.debug("Computed new affinity after node left [topVer=" + topVer + - ", waitGrps=" + (info != null ? groupNames(info.waitGrps.keySet()) : null) + ']'); - } - } + Map result = onReassignmentEnforced(fut); - return CacheGroupAffinityMessage.createAffinityDiffMessages(diff); + return result; } /** @@ -1862,8 +1711,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @throws IgniteCheckedException If failed. */ public Map onCustomEventWithEnforcedAffinityReassignment( - final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException - { + final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException { assert DiscoveryCustomEvent.requiresCentralizedAffinityAssignment(fut.firstEvent()); Map result = onReassignmentEnforced(fut); @@ -1879,8 +1727,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @throws IgniteCheckedException If failed. */ private Map onReassignmentEnforced( - final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException - { + final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException { final ExchangeDiscoveryEvents evts = fut.context().events(); forAllRegisteredCacheGroups(new IgniteInClosureX() { @@ -1966,7 +1813,8 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @param crd Coordinator flag. * @throws IgniteCheckedException If failed. */ - public void onBaselineTopologyChanged(final GridDhtPartitionsExchangeFuture fut, boolean crd) throws IgniteCheckedException { + public void onBaselineTopologyChanged(final GridDhtPartitionsExchangeFuture fut, + boolean crd) throws IgniteCheckedException { assert !fut.firstEvent().eventNode().isClient(); WaitRebalanceInfo waitRebalanceInfo = initAffinityOnNodeJoin(fut, crd); @@ -2094,8 +1942,8 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @param discoCache Discovery data cache. * @param affCache Affinity. * @param fetchFut Affinity fetch future. - * @throws IgniteCheckedException If failed. * @return Affinity assignment response. + * @throws IgniteCheckedException If failed. */ private GridDhtAffinityAssignmentResponse fetchAffinity( AffinityTopologyVersion topVer, @@ -2139,10 +1987,11 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * * @param fut Exchange future. * @param crd Coordinator flag. - * @throws IgniteCheckedException If failed. * @return {@code True} if affinity should be assigned by coordinator. + * @throws IgniteCheckedException If failed. */ - public boolean onCentralizedAffinityChange(final GridDhtPartitionsExchangeFuture fut, boolean crd) throws IgniteCheckedException { + public boolean onCentralizedAffinityChange(final GridDhtPartitionsExchangeFuture fut, + boolean crd) throws IgniteCheckedException { assert (fut.events().hasServerLeft() && !fut.firstEvent().eventNode().isClient()) || DiscoveryCustomEvent.requiresCentralizedAffinityAssignment(fut.firstEvent()) : fut.firstEvent(); @@ -2169,8 +2018,8 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap /** * @param fut Exchange future. * @param newAff {@code True} if there are no older nodes with affinity info available. - * @throws IgniteCheckedException If failed. * @return Future completed when caches initialization is done. + * @throws IgniteCheckedException If failed. */ public IgniteInternalFuture initCoordinatorCaches( final GridDhtPartitionsExchangeFuture fut, @@ -2241,10 +2090,10 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap } GridDhtAssignmentFetchFuture fetchFut = new GridDhtAssignmentFetchFuture( - cctx, - desc.groupId(), - futureToFetchAffinity.topologyVersion(), - futureToFetchAffinity.events().discoveryCache() + cctx, + desc.groupId(), + futureToFetchAffinity.topologyVersion(), + futureToFetchAffinity.events().discoveryCache() ); fetchFut.init(false); @@ -2255,13 +2104,13 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap fetchFut.listen(new IgniteInClosureX>() { @Override public void applyx(IgniteInternalFuture fetchFut) - throws IgniteCheckedException { + throws IgniteCheckedException { fetchAffinity( - futureToFetchAffinity0.topologyVersion(), - futureToFetchAffinity0.events(), - futureToFetchAffinity0.events().discoveryCache(), - aff, - (GridDhtAssignmentFetchFuture)fetchFut + futureToFetchAffinity0.topologyVersion(), + futureToFetchAffinity0.events(), + futureToFetchAffinity0.events().discoveryCache(), + aff, + (GridDhtAssignmentFetchFuture)fetchFut ); aff.calculate(topVer, fut.events(), fut.events().discoveryCache()); @@ -2375,30 +2224,30 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap if (cctx.localNode().isClient() && cctx.cache().cacheGroup(desc.groupId()) == null) return; - CacheGroupHolder cache = getOrCreateGroupHolder(evts.topologyVersion(), desc); + CacheGroupHolder grpHolder = getOrCreateGroupHolder(evts.topologyVersion(), desc); - boolean latePrimary = cache.rebalanceEnabled; + boolean latePrimary = grpHolder.rebalanceEnabled; boolean grpAdded = evts.nodeJoined(desc.receivedFrom()); initAffinityOnNodeJoin(evts, grpAdded, - cache.affinity(), + grpHolder.affinity(), crd ? waitRebalanceInfo : null, latePrimary); if (crd && grpAdded) { - AffinityAssignment aff = cache.aff.cachedAffinity(cache.aff.lastVersion()); + AffinityAssignment aff = grpHolder.aff.cachedAffinity(grpHolder.aff.lastVersion()); assert evts.topologyVersion().equals(aff.topologyVersion()) : "Unexpected version [" + - "grp=" + cache.aff.cacheOrGroupName() + + "grp=" + grpHolder.aff.cacheOrGroupName() + ", evts=" + evts.topologyVersion() + - ", aff=" + cache.aff.lastVersion() + ']'; + ", aff=" + grpHolder.aff.lastVersion() + ']'; Map map = affinityFullMap(aff); for (GridDhtPartitionMap map0 : map.values()) - cache.topology(fut.context().events().discoveryCache()).update(fut.exchangeId(), map0, true); + grpHolder.topology(fut.context().events().discoveryCache()).update(fut.exchangeId(), map0, true); } cctx.exchange().exchangerUpdateHeartbeat(); @@ -2466,77 +2315,40 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap assert affTopVer.topologyVersion() > 0 : "Affinity is not initialized [grp=" + aff.cacheOrGroupName() + ", topVer=" + affTopVer + ", node=" + cctx.localNodeId() + ']'; - assert aff.idealAssignmentRaw() != null : "Previous assignment is not available."; + List> curAff = aff.assignments(affTopVer); + + assert aff.idealAssignment() != null : "Previous assignment is not available."; - IdealAffinityAssignment idealAssignment = aff.calculate(evts.topologyVersion(), evts, evts.discoveryCache()); - List> curAssignment = aff.assignments(affTopVer); + List> idealAssignment = aff.calculate(evts.topologyVersion(), evts, evts.discoveryCache()).assignment(); List> newAssignment = null; if (latePrimary) { - BitSet processedPartitions = new BitSet(curAssignment.size()); + for (int p = 0; p < idealAssignment.size(); p++) { + List newNodes = idealAssignment.get(p); + List curNodes = curAff.get(p); - // Late affinity assignment to changed primaries. - for (ClusterNode joinedNode : evts.joinedServerNodes()) { - Set primaries = idealAssignment.idealPrimaries(joinedNode); - - for (int p : primaries) { - List curNodes = curAssignment.get(p); - - if (curNodes.isEmpty()) - continue; - - ClusterNode curPrimary = curNodes.get(0); + ClusterNode curPrimary = !curNodes.isEmpty() ? curNodes.get(0) : null; + ClusterNode newPrimary = !newNodes.isEmpty() ? newNodes.get(0) : null; + if (curPrimary != null && newPrimary != null && !curPrimary.equals(newPrimary)) { assert cctx.discovery().node(evts.topologyVersion(), curPrimary.id()) != null : curPrimary; - List idealNodes = idealAssignment.assignment().get(p); - - List newNodes = latePrimaryAssignment(aff, + List nodes0 = latePrimaryAssignment(aff, p, curPrimary, - idealNodes, - rebalanceInfo); - - if (newAssignment == null) - newAssignment = new ArrayList<>(idealAssignment.assignment()); - - newAssignment.set(p, newNodes); - - processedPartitions.set(p); - } - } - - Set partitionsWithChangedPrimary = aff.partitionPrimariesDifferentToIdeal(affTopVer); - - for (int p : partitionsWithChangedPrimary) { - // Already processed above. - if (processedPartitions.get(p)) - continue; - - List curNodes = curAssignment.get(p); - - if (curNodes.isEmpty()) - continue; - - List idealOwners = idealAssignment.assignment().get(p); - - if (!curNodes.get(0).equals(idealOwners.get(0))) { - List newNodes = latePrimaryAssignment(aff, - p, - curNodes.get(0), - idealOwners, + newNodes, rebalanceInfo); if (newAssignment == null) - newAssignment = new ArrayList<>(idealAssignment.assignment()); + newAssignment = new ArrayList<>(idealAssignment); - newAssignment.set(p, newNodes); + newAssignment.set(p, nodes0); } } } if (newAssignment == null) - newAssignment = idealAssignment.assignment(); + newAssignment = idealAssignment; aff.initialize(evts.topologyVersion(), newAssignment); } @@ -2608,14 +2420,13 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap } /** - * Initializes current affinity assignment based on partitions availability. - * Nodes that have most recent data will be considered affinity nodes. + * Initializes current affinity assignment based on partitions availability. Nodes that have most recent data will + * be considered affinity nodes. * * @param topVer Topology version. * @param fut Exchange future. * @param c Closure converting affinity diff. * @param initAff {@code True} if need initialize affinity. - * * @return Affinity assignment for each of registered cache group. */ private Map>> initAffinityBasedOnPartitionsAvailability( @@ -2989,7 +2800,7 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap GridCacheSharedContext cctx, CacheGroupDescriptor grpDesc, AffinityTopologyVersion topVer - ) throws IgniteCheckedException { + ) throws IgniteCheckedException { return create(cctx, grpDesc, topVer, null); } @@ -3128,14 +2939,13 @@ public class CacheAffinitySharedManager extends GridCacheSharedManagerAdap * @param waitNode Node rebalancing data. * @param assignment New assignment. */ - void add(Integer grpId, Integer part, UUID waitNode, List assignment) { - assert !F.isEmpty(assignment) : assignment; - + void add(Integer grpId, Integer part, UUID waitNode, @Nullable List assignment) { deploymentIds.putIfAbsent(grpId, cachesRegistry.group(grpId).deploymentId()); waitGrps.computeIfAbsent(grpId, k -> new HashMap<>()).put(part, waitNode); - assignments.computeIfAbsent(grpId, k -> new HashMap<>()).put(part, assignment); + if (assignment != null) + assignments.computeIfAbsent(grpId, k -> new HashMap<>()).put(part, assignment); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryInfoCollection.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryInfoCollection.java index 968afd5..b6da77f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryInfoCollection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryInfoCollection.java @@ -128,4 +128,23 @@ public class CacheEntryInfoCollection implements Message { @Override public byte fieldsCount() { return 1; } + + /** {@inheritDoc} */ + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("["); + + for (int i = 0; i < infos().size(); i++) { + GridCacheEntryInfo info = infos().get(i); + + Object k = info.key().value(null, false); + + b.append("[key=").append(k == null ? "null" : k).append(", ver="). + append(info.version()).append(", val=").append(info.value()).append(']'); + } + + b.append(']'); + + return b.toString(); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java index 29efa76..68dffbf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java @@ -65,6 +65,7 @@ import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.mxbean.CacheGroupMetricsMXBean; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT; import static org.apache.ignite.cache.CacheMode.LOCAL; import static org.apache.ignite.cache.CacheMode.REPLICATED; @@ -182,6 +183,8 @@ public class CacheGroupContext { /** Statistics holder to track IO operations for data pages. */ private final IoStatisticsHolder statHolderData; + /** */ + private volatile boolean hasAtomicCaches; /** * @param ctx Context. @@ -357,6 +360,9 @@ public class CacheGroupContext { if (!drEnabled && cctx.isDrEnabled()) drEnabled = true; + + if (!hasAtomicCaches) + hasAtomicCaches = cctx.config().getAtomicityMode() == ATOMIC; } /** @@ -1278,4 +1284,11 @@ public class CacheGroupContext { public IoStatisticsHolder statisticsHolderData() { return statHolderData; } + + /** + * @return {@code True} if group has atomic caches. + */ + public boolean hasAtomicCaches() { + return hasAtomicCaches; + } } 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 5ca9c41..54dc706 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 @@ -1542,10 +1542,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme if (cctx.deferredDelete() && deletedUnlocked() && !isInternal() && !detached()) deletedUnlocked(false); - updateCntr0 = nextPartitionCounter(topVer, tx == null || tx.local(), updateCntr); - - if (updateCntr != null && updateCntr != 0) - updateCntr0 = updateCntr; + updateCntr0 = nextPartitionCounter(tx, updateCntr); if (tx != null && cctx.group().persistenceEnabled() && cctx.group().walEnabled()) logPtr = logTxUpdate(tx, val, expireTime, updateCntr0); @@ -1765,10 +1762,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme } } - updateCntr0 = nextPartitionCounter(topVer, tx == null || tx.local(), updateCntr); - - if (updateCntr != null && updateCntr != 0) - updateCntr0 = updateCntr; + updateCntr0 = nextPartitionCounter(tx, updateCntr); if (tx != null && cctx.group().persistenceEnabled() && cctx.group().walEnabled()) logPtr = logTxUpdate(tx, null, 0, updateCntr0); @@ -2189,7 +2183,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme cctx.cache().metrics0().onInvokeRemove(old != null); if (lsnrCol != null) { - long updateCntr = nextPartitionCounter(AffinityTopologyVersion.NONE, true, null); + long updateCntr = nextPartitionCounter(AffinityTopologyVersion.NONE, true, false, null); cctx.continuousQueries().onEntryUpdated( lsnrCol, @@ -2368,12 +2362,9 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme else evtVal = (CacheObject)writeObj; - long updateCntr0 = nextPartitionCounter(topVer, primary, updateCntr); + assert !primary && updateCntr != null; - if (updateCntr != null) - updateCntr0 = updateCntr; - - onUpdateFinished(updateCntr0); + onUpdateFinished(updateCntr); cctx.continuousQueries().onEntryUpdated( key, @@ -2383,7 +2374,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme partition(), primary, false, - updateCntr0, + updateCntr, null, topVer); } @@ -3447,7 +3438,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme long updateCntr = 0; if (!preload) - updateCntr = nextPartitionCounter(topVer, true, null); + updateCntr = nextPartitionCounter(topVer, true, true, null); if (walEnabled) { if (cctx.mvccEnabled()) { @@ -3536,10 +3527,20 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme /** * @param topVer Topology version for current operation. * @param primary Primary node update flag. + * @param initial {@code True} if initial value. * @param primaryCntr Counter assigned on primary node. * @return Update counter. */ - protected long nextPartitionCounter(AffinityTopologyVersion topVer, boolean primary, @Nullable Long primaryCntr) { + protected long nextPartitionCounter(AffinityTopologyVersion topVer, boolean primary, boolean initial, + @Nullable Long primaryCntr) { + return 0; + } + + /** + * @param tx Tx. + * @param updateCntr Update counter. + */ + protected long nextPartitionCounter(IgniteInternalTx tx, @Nullable Long updateCntr) { return 0; } @@ -5574,8 +5575,8 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme cctx.cacheId(), entry.key(), val, - res.resultType() == ResultType.PREV_NULL ? CREATE : - (res.resultType() == ResultType.REMOVED_NOT_NULL) ? DELETE : UPDATE, + res.resultType() == ResultType.PREV_NULL ? CREATE : + (res.resultType() == ResultType.REMOVED_NOT_NULL) ? DELETE : UPDATE, tx.nearXidVersion(), newVer, expireTime, @@ -5751,7 +5752,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme oldRow); treeOp = oldRow != null && oldRow.link() == newRow.link() ? - IgniteTree.OperationType.NOOP : IgniteTree.OperationType.PUT; + IgniteTree.OperationType.IN_PLACE : IgniteTree.OperationType.PUT; } else treeOp = oldRow != null ? IgniteTree.OperationType.REMOVE : IgniteTree.OperationType.NOOP; @@ -6376,10 +6377,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme ", locNodeId=" + cctx.localNodeId() + ']'; } - long updateCntr0 = entry.nextPartitionCounter(topVer, primary, updateCntr); - - if (updateCntr != null) - updateCntr0 = updateCntr; + long updateCntr0 = entry.nextPartitionCounter(topVer, primary, false, updateCntr); entry.logUpdate(op, updated, newVer, newExpireTime, updateCntr0); @@ -6466,10 +6464,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme // Must persist inside synchronization in non-tx mode. cctx.store().remove(null, entry.key); - long updateCntr0 = entry.nextPartitionCounter(topVer, primary, updateCntr); - - if (updateCntr != null) - updateCntr0 = updateCntr; + long updateCntr0 = entry.nextPartitionCounter(topVer, primary, false, updateCntr); entry.logUpdate(op, null, newVer, 0, updateCntr0); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java index 199f725..f5ba7a2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java @@ -1773,7 +1773,9 @@ public class GridCachePartitionExchangeManager extends GridCacheSharedMana null, msg.partsToReload(cctx.localNodeId(), grpId), partsSizes.getOrDefault(grpId, Collections.emptyMap()), - msg.topologyVersion()); + msg.topologyVersion(), + null + ); } } @@ -1815,8 +1817,8 @@ public class GridCachePartitionExchangeManager extends GridCacheSharedMana try { if (msg.exchangeId() == null) { - if (log.isTraceEnabled()) - log.trace("Received local partition update [nodeId=" + node.id() + ", parts=" + + if (log.isDebugEnabled()) + log.debug("Received local partition update [nodeId=" + node.id() + ", parts=" + msg + ']'); boolean updated = false; @@ -1865,7 +1867,7 @@ public class GridCachePartitionExchangeManager extends GridCacheSharedMana U.warn(log, "Client node tries to connect but its exchange " + "info is cleaned up from exchange history. " + "Consider increasing 'IGNITE_EXCHANGE_HISTORY_SIZE' property " + - "or start clients in smaller batches. " + + "or start clients in smaller batches. " + "Current settings and versions: " + "[IGNITE_EXCHANGE_HISTORY_SIZE=" + EXCHANGE_HISTORY_SIZE + ", " + "initVer=" + initVer + ", " + diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 48797ee..ec4b8cf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -119,7 +119,6 @@ import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaS import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageLifecycleListener; import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadOnlyMetastorage; import org.apache.ignite.internal.processors.cache.persistence.partstate.GroupPartitionId; -import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionRecoverState; import org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteCacheSnapshotManager; import org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotDiscoveryMessage; import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; @@ -236,6 +235,10 @@ public class GridCacheProcessor extends GridProcessorAdapter { private static final String INVALID_REGION_CONFIGURATION_MESSAGE = "Failed to join node " + "(Incompatible data region configuration [region=%s, locNodeId=%s, isPersistenceEnabled=%s, rmtNodeId=%s, isPersistenceEnabled=%s])"; + /** Template of message of failed node join because encryption settings are different for the same cache. */ + private static final String ENCRYPT_MISMATCH_MESSAGE = "Failed to join node to the cluster " + + "(encryption settings are different for cache '%s' : local=%s, remote=%s.)"; + /** */ private final boolean startClientCaches = IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_START_CACHES_ON_JOIN, false); @@ -1069,7 +1072,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { } /** - * @param node Remote node to check. + * @param rmtNode Remote node to check. * @return Data storage configuration */ private DataStorageConfiguration extractDataStorage(ClusterNode rmtNode) { @@ -3489,12 +3492,12 @@ public class GridCacheProcessor extends GridProcessorAdapter { } } - DynamicCacheDescriptor localDesc = cacheDescriptor(cacheInfo.cacheData().config().getName()); + DynamicCacheDescriptor locDesc = cacheDescriptor(cacheInfo.cacheData().config().getName()); - if (localDesc == null) + if (locDesc == null) continue; - QuerySchemaPatch schemaPatch = localDesc.makeSchemaPatch(cacheInfo.cacheData().queryEntities()); + QuerySchemaPatch schemaPatch = locDesc.makeSchemaPatch(cacheInfo.cacheData().queryEntities()); if (schemaPatch.hasConflicts() || (isGridActive && !schemaPatch.isEmpty())) { if (errorMsg.length() > 0) @@ -3502,9 +3505,22 @@ public class GridCacheProcessor extends GridProcessorAdapter { if (schemaPatch.hasConflicts()) errorMsg.append(String.format(MERGE_OF_CONFIG_CONFLICTS_MESSAGE, - localDesc.cacheName(), schemaPatch.getConflictsMessage())); + locDesc.cacheName(), schemaPatch.getConflictsMessage())); else - errorMsg.append(String.format(MERGE_OF_CONFIG_REQUIRED_MESSAGE, localDesc.cacheName())); + errorMsg.append(String.format(MERGE_OF_CONFIG_REQUIRED_MESSAGE, locDesc.cacheName())); + } + + // This check must be done on join, otherwise group encryption key will be + // written to metastore regardless of validation check and could trigger WAL write failures. + boolean locEnc = locDesc.cacheConfiguration().isEncryptionEnabled(); + boolean rmtEnc = cacheInfo.cacheData().config().isEncryptionEnabled(); + + if (locEnc != rmtEnc) { + if (errorMsg.length() > 0) + errorMsg.append("\n"); + + // Message will be printed on remote node, so need to swap local and remote. + errorMsg.append(String.format(ENCRYPT_MISMATCH_MESSAGE, locDesc.cacheName(), rmtEnc, locEnc)); } } @@ -6016,7 +6032,7 @@ public class GridCacheProcessor extends GridProcessorAdapter { */ private void restorePartitionStates( Collection forGroups, - Map partitionStates + Map partitionStates ) throws IgniteCheckedException { long startRestorePart = U.currentTimeMillis(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java index 2254c5e..3623fd9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedTtlCleanupManager.java @@ -23,6 +23,7 @@ import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.failure.FailureContext; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.internal.NodeStoppingException; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.util.worker.GridWorker; import org.apache.ignite.thread.IgniteThread; @@ -164,7 +165,13 @@ public class GridCacheSharedTtlCleanupManager extends GridCacheSharedManagerAdap } } catch (Throwable t) { - if (!(X.hasCause(t, IgniteInterruptedCheckedException.class, InterruptedException.class))) + if (X.hasCause(t, NodeStoppingException.class)) { + isCancelled = true; // Treat node stopping as valid worker cancellation. + + return; + } + + if (!(t instanceof IgniteInterruptedCheckedException || t instanceof InterruptedException)) err = t; throw t; 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 48c86b9..cc5dd42 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 @@ -849,6 +849,7 @@ public class GridCacheUtils { return tx.getClass().getSimpleName() + "[xid=" + tx.xid() + ", xidVersion=" + tx.xidVersion() + + ", nearXidVersion=" + tx.nearXidVersion() + ", concurrency=" + tx.concurrency() + ", isolation=" + tx.isolation() + ", state=" + tx.state() + @@ -857,7 +858,7 @@ public class GridCacheUtils { ", nodeId=" + tx.nodeId() + ", timeout=" + tx.timeout() + ", duration=" + (U.currentTimeMillis() - tx.startTime()) + - (tx instanceof GridNearTxLocal ? ", label=" + ((GridNearTxLocal)tx).label() : "") + + (tx instanceof GridNearTxLocal ? ", label=" + tx.label() : "") + ']'; } 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 b7e8ec7..74a0b30 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 @@ -31,8 +31,9 @@ import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; import org.apache.ignite.internal.processors.cache.persistence.CacheSearchRow; import org.apache.ignite.internal.processors.cache.persistence.RootPage; import org.apache.ignite.internal.processors.cache.persistence.RowStore; +import org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow; import org.apache.ignite.internal.processors.cache.persistence.partstate.GroupPartitionId; -import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionRecoverState; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorage; import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; import org.apache.ignite.internal.processors.cache.tree.PendingEntriesTree; import org.apache.ignite.internal.processors.cache.tree.mvcc.data.MvccUpdateResult; @@ -90,7 +91,7 @@ public interface IgniteCacheOffheapManager { * @return Number of processed partitions. * @throws IgniteCheckedException If failed. */ - long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException; + long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException; /** * Partition counter update callback. May be overridden by plugin-provided subclasses. @@ -104,9 +105,10 @@ public interface IgniteCacheOffheapManager { * Initial counter will be updated on state restore only * * @param part Partition - * @param cntr New initial counter + * @param start Start. + * @param delta Delta. */ - public void onPartitionInitialCounterUpdated(int part, long cntr); + public void onPartitionInitialCounterUpdated(int part, long start, long delta); /** * Partition counter provider. May be overridden by plugin-provided subclasses. @@ -584,6 +586,13 @@ public interface IgniteCacheOffheapManager { */ interface CacheDataStore { /** + * Initialize data store if it exists. + * + * @return {@code True} if initialized. + */ + boolean init(); + + /** * @return Partition ID. */ int partId(); @@ -594,13 +603,6 @@ public interface IgniteCacheOffheapManager { String name(); /** - * @param size Size to init. - * @param updCntr Update counter to init. - * @param cacheSizes Cache sizes if store belongs to group containing multiple caches. - */ - void init(long size, long updCntr, @Nullable Map cacheSizes); - - /** * @param cacheId Cache ID. * @return Size. */ @@ -630,22 +632,36 @@ public interface IgniteCacheOffheapManager { void updateSize(int cacheId, long delta); /** - * @return Update counter. + * @return Update counter (LWM). */ long updateCounter(); /** + * @return Reserved counter (HWM). + */ + long reservedCounter(); + + /** + * @return Update counter or {@code null} if store is not yet created. + */ + @Nullable PartitionUpdateCounter partUpdateCounter(); + + /** + * @param delta Delta. + */ + long reserve(long delta); + + /** * @param val Update counter. */ void updateCounter(long val); /** * Updates counters from start value by delta value. - * * @param start Start. - * @param delta Delta + * @param delta Delta. */ - void updateCounter(long start, long delta); + boolean updateCounter(long start, long delta); /** * @return Next update counter. @@ -1017,9 +1033,10 @@ public interface IgniteCacheOffheapManager { public RowStore rowStore(); /** - * @param cntr Counter. + * @param start Counter. + * @param delta Delta. */ - public void updateInitialCounter(long cntr); + public void updateInitialCounter(long start, long delta); /** * Inject rows cache cleaner. @@ -1047,5 +1064,15 @@ public interface IgniteCacheOffheapManager { * @throws IgniteCheckedException If failed. */ public void preload() throws IgniteCheckedException; + + /** + * Reset counters for partition. + */ + void resetUpdateCounter(); + + /** + * Partition storage. + */ + public PartitionMetaStorage partStorage(); } } 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 a0ebcdc..3706754 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 @@ -36,6 +36,9 @@ import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.failure.FailureContext; +import org.apache.ignite.failure.FailureType; import org.apache.ignite.internal.NodeStoppingException; import org.apache.ignite.internal.pagemem.FullPageId; import org.apache.ignite.internal.pagemem.wal.record.delta.DataPageMvccMarkUpdatedRecord; @@ -59,8 +62,9 @@ import org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapt import org.apache.ignite.internal.processors.cache.persistence.CacheSearchRow; import org.apache.ignite.internal.processors.cache.persistence.RootPage; import org.apache.ignite.internal.processors.cache.persistence.RowStore; +import org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow; import org.apache.ignite.internal.processors.cache.persistence.partstate.GroupPartitionId; -import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionRecoverState; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorage; import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO; @@ -139,6 +143,10 @@ import static org.apache.ignite.internal.util.IgniteTree.OperationType.PUT; */ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager { /** */ + private final boolean failNodeOnPartitionInconsistency = Boolean.getBoolean( + IgniteSystemProperties.IGNITE_FAIL_NODE_ON_UNRECOVERABLE_PARTITION_INCONSISTENCY); + + /** */ protected GridCacheSharedContext ctx; /** */ @@ -251,7 +259,7 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager } /** {@inheritDoc} */ - @Override public long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException { + @Override public long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException { return 0; // No-op. } @@ -692,7 +700,7 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager } /** {@inheritDoc} */ - @Override public void onPartitionInitialCounterUpdated(int part, long cntr) { + @Override public void onPartitionInitialCounterUpdated(int part, long start, long delta) { // No-op. } @@ -1398,7 +1406,7 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager private final CacheDataTree dataTree; /** Update counter. */ - protected final PartitionUpdateCounter pCntr = new PartitionUpdateCounter(log); + protected final PartitionUpdateCounter pCntr; /** Partition size. */ private final AtomicLong storageSize = new AtomicLong(); @@ -1431,6 +1439,14 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager this.name = name; this.rowStore = rowStore; this.dataTree = dataTree; + if (grp.mvccEnabled()) + pCntr = new PartitionMvccTxUpdateCounterImpl(); + else if (grp.hasAtomicCaches()) + pCntr = new PartitionAtomicUpdateCounterImpl(); + else { + pCntr = ctx.logger(PartitionTxUpdateCounterDebugWrapper.class).isDebugEnabled() ? + new PartitionTxUpdateCounterDebugWrapper(grp, partId) : new PartitionTxUpdateCounterImpl(); + } } /** @@ -1448,6 +1464,11 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager } /** {@inheritDoc} */ + @Override public boolean init() { + return false; + } + + /** {@inheritDoc} */ @Override public int partId() { return partId; } @@ -1527,14 +1548,17 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager return pCntr.initial(); } - /** {@inheritDoc} */ - @Override public void updateInitialCounter(long cntr) { - pCntr.updateInitial(cntr); + /** {@inheritDoc} + * @param start Start. + * @param delta Delta. + */ + @Override public void updateInitialCounter(long start, long delta) { + pCntr.updateInitial(start, delta); } /** {@inheritDoc} */ @Override public long getAndIncrementUpdateCounter(long delta) { - return pCntr.getAndAdd(delta); + return pCntr.reserve(delta); } /** {@inheritDoc} */ @@ -1543,13 +1567,39 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager } /** {@inheritDoc} */ + @Override public long reservedCounter() { + return pCntr.reserved(); + } + + /** {@inheritDoc} */ + @Override public PartitionUpdateCounter partUpdateCounter() { + return pCntr; + } + + /** {@inheritDoc} */ + @Override public long reserve(long delta) { + return pCntr.reserve(delta); + } + + /** {@inheritDoc} */ @Override public void updateCounter(long val) { - pCntr.update(val); + try { + pCntr.update(val); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to update partition counter. " + + "Most probably a node with most actual data is out of topology or data streamer is used " + + "in preload mode (allowOverride=false) concurrently with cache transactions [grpName=" + + grp.name() + ", partId=" + partId + ']', e); + + if (failNodeOnPartitionInconsistency) + ctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); + } } /** {@inheritDoc} */ - @Override public void updateCounter(long start, long delta) { - pCntr.update(start, delta); + @Override public boolean updateCounter(long start, long delta) { + return pCntr.update(start, delta); } /** {@inheritDoc} */ @@ -1638,6 +1688,7 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager } case NOOP: + case IN_PLACE: break; default: @@ -2891,9 +2942,14 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager rowStore().setRowCacheCleaner(rowCacheCleaner); } - /** {@inheritDoc} */ - @Override public void init(long size, long updCntr, @Nullable Map cacheSizes) { - pCntr.init(updCntr); + /** + * @param size Size to init. + * @param updCntr Update counter. + * @param cacheSizes Cache sizes if store belongs to group containing multiple caches. + * @param cntrUpdData Counter updates. + */ + public void restoreState(long size, long updCntr, @Nullable Map cacheSizes, byte[] cntrUpdData) { + pCntr.init(updCntr, cntrUpdData); storageSize.set(size); @@ -2913,6 +2969,16 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager // No-op. } + /** {@inheritDoc} */ + @Override public void resetUpdateCounter() { + pCntr.reset(); + } + + /** {@inheritDoc} */ + @Override public PartitionMetaStorage partStorage() { + return null; + } + /** * @param cctx Cache context. * @param key Key. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionAtomicUpdateCounterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionAtomicUpdateCounterImpl.java new file mode 100644 index 0000000..317c679 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionAtomicUpdateCounterImpl.java @@ -0,0 +1,155 @@ +/* + * 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; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicLong; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.util.GridEmptyIterator; +import org.apache.ignite.internal.util.GridLongList; +import org.jetbrains.annotations.Nullable; + +/** + * Partition update counter for non-tx scenarios without support for tracking missed updates. + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 + */ +public class PartitionAtomicUpdateCounterImpl implements PartitionUpdateCounter { + /** Counter of applied updates in partition. */ + private final AtomicLong cntr = new AtomicLong(); + + /** + * Initial counter is set to update with max sequence number after WAL recovery. + */ + private long initCntr; + + /** {@inheritDoc} */ + @Override public void init(long initUpdCntr, @Nullable byte[] cntrUpdData) { + cntr.set(initUpdCntr); + + initCntr = initUpdCntr; + } + + /** {@inheritDoc} */ + @Override public long initial() { + return initCntr; + } + + /** {@inheritDoc} */ + @Override public long get() { + return cntr.get(); + } + + /** {@inheritDoc} */ + @Override public long next() { + return cntr.incrementAndGet(); + } + + /** {@inheritDoc} */ + @SuppressWarnings("StatementWithEmptyBody") + @Override public void update(long val) { + long cur; + + while(val > (cur = cntr.get()) && !cntr.compareAndSet(cur, val)); + } + + /** + * Updates counter by delta from start position. + * + * @param start Start. + * @param delta Delta. + */ + @Override public boolean update(long start, long delta) { + return false; // Prevent RollbackRecord in mixed tx-atomic mode. + } + + /** + * Updates initial counter on recovery. Not thread-safe. + * + * @param start Start. + * @param delta Delta. + */ + @Override public synchronized void updateInitial(long start, long delta) { + update(start + delta); + + initCntr = get(); + } + + /** {@inheritDoc} */ + @Override public GridLongList finalizeUpdateCounters() { + return new GridLongList(0); + } + + /** {@inheritDoc} */ + @Override public long reserve(long delta) { + return next(delta); + } + + /** {@inheritDoc} */ + @Override public long next(long delta) { + return cntr.getAndAdd(delta); + } + + /** {@inheritDoc} */ + @Override public boolean sequential() { + return true; + } + + /** {@inheritDoc} */ + @Override public @Nullable byte[] getBytes() { + return null; + } + + /** {@inheritDoc} */ + @Override public synchronized void reset() { + initCntr = 0; + + cntr.set(0); + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + PartitionAtomicUpdateCounterImpl cntr = (PartitionAtomicUpdateCounterImpl)o; + + return this.cntr.get() == cntr.cntr.get(); + } + + /** {@inheritDoc} */ + @Override public long reserved() { + return get(); + } + + /** {@inheritDoc} */ + @Override public synchronized boolean empty() { + return get() == 0; + } + + /** {@inheritDoc} */ + @Override public Iterator iterator() { + return new GridEmptyIterator<>(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Counter [init=" + initCntr + ", val=" + get() + ']'; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionMvccTxUpdateCounterImpl.java similarity index 50% copy from modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java copy to modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionMvccTxUpdateCounterImpl.java index 133f0a1..2f5d77a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionMvccTxUpdateCounterImpl.java @@ -15,38 +15,19 @@ * limitations under the License. */ -package org.apache.ignite.internal.processors.cache.persistence; - -import org.apache.ignite.IgniteCheckedException; +package org.apache.ignite.internal.processors.cache; /** - * Simple interface for data, store in some RowStore. + * Update counter implementation for MVCC mode. */ -public interface Storable { - /** - * @param link Link for this row. - */ - public void link(long link); - - /** - * @return Link for this row. - */ - public long link(); - - /** - * @return Partition. - */ - public int partition(); - - /** - * @return Row size in page. - * @throws IgniteCheckedException If failed. - */ - public int size() throws IgniteCheckedException; +public class PartitionMvccTxUpdateCounterImpl extends PartitionTxUpdateCounterImpl { + /** {@inheritDoc} */ + @Override public long reserve(long delta) { + return next(delta); + } - /** - * @return Row header size in page. Header is indivisible part of row - * which is entirely available on the very first page followed by the row link. - */ - public int headerSize(); + /** {@inheritDoc} */ + @Override public long reserved() { + return get(); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterDebugWrapper.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterDebugWrapper.java new file mode 100644 index 0000000..a63479b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterDebugWrapper.java @@ -0,0 +1,201 @@ +/* + * 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; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.util.GridLongList; +import org.apache.ignite.internal.util.typedef.internal.SB; +import org.jetbrains.annotations.Nullable; + +/** + * Update counter implementation useful for debugging. + */ +public class PartitionTxUpdateCounterDebugWrapper extends PartitionTxUpdateCounterImpl { + /** */ + private IgniteLogger log; + + /** */ + private int partId; + + /** */ + private CacheGroupContext grp; + + /** + * @param grp Group. + * @param partId Part id. + */ + public PartitionTxUpdateCounterDebugWrapper(CacheGroupContext grp, int partId) { + this.log = grp.shared().logger(getClass()); + this.partId = partId; + this.grp = grp; + } + + /** {@inheritDoc} */ + @Override public void init(long initUpdCntr, @Nullable byte[] cntrUpdData) { + super.init(initUpdCntr, cntrUpdData); + + log.debug("[op=init" + + ", grpId=" + grp.groupId() + + ", grpName=" + grp.cacheOrGroupName() + + ", caches=" + grp.caches() + + ", atomicity=" + grp.config().getAtomicityMode() + + ", syncMode=" + grp.config().getWriteSynchronizationMode() + + ", mode=" + grp.config().getCacheMode() + + ", partId=" + partId + + ", gapsLen=" + (cntrUpdData != null ? cntrUpdData.length : 0) + + ", cur=" + toString() + + ']'); + } + + /** {@inheritDoc} */ + @Override public void updateInitial(long start, long delta) { + SB sb = new SB(); + + sb.a("[op=updateInitial" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", range=(" + start + "," + delta + ")" + + ", before=" + toString()); + + try { + super.updateInitial(start, delta); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public long next() { + SB sb = new SB(); + + sb.a("[op=next" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", before=" + toString()); + + try { + return super.next(); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public long next(long delta) { + SB sb = new SB(); + + sb.a("[op=next" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", delta=" + delta + + ", before=" + toString()); + + try { + return super.next(); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public synchronized void update(long val) throws IgniteCheckedException { + SB sb = new SB(); + + sb.a("[op=set" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", val=" + val + + ", before=" + toString()); + + try { + super.update(val); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public synchronized GridLongList finalizeUpdateCounters() { + SB sb = new SB(); + + sb.a("[op=finalizeUpdateCounters" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", before=" + toString() + + ']'); + + try { + return super.finalizeUpdateCounters(); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public synchronized long reserve(long delta) { + SB sb = new SB(); + + sb.a("[op=reserve" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", delta=" + delta + + ", before=" + toString()); + + try { + return super.reserve(delta); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + } + + /** {@inheritDoc} */ + @Override public synchronized boolean update(long start, long delta) { + SB sb = new SB(); + + sb.a("[op=update" + + ", grpId=" + grp.groupId() + + ", partId=" + partId + + ", delta=(" + start + "," + delta + ")" + + ", before=" + toString()); + + boolean updated = false; + + try { + updated = super.update(start, delta); + } + finally { + log.debug(sb.a(", after=" + toString() + + ']').toString()); + } + + return updated; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java new file mode 100644 index 0000000..f8f236f --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java @@ -0,0 +1,450 @@ +/* + * 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; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicLong; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.processors.datastreamer.DataStreamerImpl; +import org.apache.ignite.internal.util.GridLongList; +import org.apache.ignite.internal.util.typedef.F; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Update counter implementation used for transactional cache groups. + */ +public class PartitionTxUpdateCounterImpl implements PartitionUpdateCounter { + /** + * Max allowed missed updates. Overflow will trigger critical failure handler to prevent OOM. + */ + public static final int MAX_MISSED_UPDATES = 10_000; + + /** Counter updates serialization version. */ + private static final byte VERSION = 1; + + /** Queue of finished out of order counter updates. */ + private TreeSet queue = new TreeSet<>(); + + /** LWM. */ + private final AtomicLong cntr = new AtomicLong(); + + /** HWM. */ + private final AtomicLong reserveCntr = new AtomicLong(); + + /** + * Initial counter points to last sequential update after WAL recovery. + * @deprecated TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11794 + */ + @Deprecated private long initCntr; + + /** {@inheritDoc} */ + @Override public void init(long initUpdCntr, @Nullable byte[] cntrUpdData) { + cntr.set(initUpdCntr); + + initCntr = initUpdCntr; + + queue = fromBytes(cntrUpdData); + } + + /** {@inheritDoc} */ + @Override public long initial() { + return initCntr; + } + + /** {@inheritDoc} */ + @Override public long get() { + return cntr.get(); + } + + /** */ + protected synchronized long highestAppliedCounter() { + return queue.isEmpty() ? cntr.get() : queue.last().absolute(); + } + + /** + * @return Next update counter. For tx mode called by {@link DataStreamerImpl} IsolatedUpdater. + */ + @Override public long next() { + long next = cntr.incrementAndGet(); + + reserveCntr.set(next); + + return next; + } + + /** {@inheritDoc} */ + @Override public synchronized void update(long val) throws IgniteCheckedException { + // Absolute counter should be not less than last applied update. + // Otherwise supplier doesn't contain some updates and rebalancing couldn't restore consistency. + // Best behavior is to stop node by failure handler in such a case. + if (!gaps().isEmpty() && val < highestAppliedCounter()) + throw new IgniteCheckedException("New value is incompatible with current update counter state. " + + "Most probably a node with most actual data is out of topology or data streamer is used in isolated " + + "mode (allowOverride=true) concurrently with normal cache operations [val=" + val + + ", locCntr=" + this + ']'); + + long cur = cntr.get(); + + // Reserved update counter is updated only on exchange or in non-tx mode. + reserveCntr.set(Math.max(cur, val)); + + if (val <= cur) + return; + + cntr.set(val); + + if (!queue.isEmpty()) + queue.clear(); + } + + /** {@inheritDoc} */ + @Override public synchronized boolean update(long start, long delta) { + long cur = cntr.get(), next; + + if (cur > start) + return false; + + if (cur < start) { + // Try merge with adjacent gaps in sequence. + Item tmp = new Item(start, delta); + Item ref = tmp; + + NavigableSet set = queue.headSet(tmp, false); + + // Merge with previous, possibly modifying previous. + if (!set.isEmpty()) { + Item last = set.last(); + + if (last.start + last.delta == start) { + tmp = last; + + last.delta += delta; + } + else if (last.within(start) && last.within(start + delta - 1)) + return false; + } + + // Merge with next, possibly modifying previous and removing next. + if (!(set = queue.tailSet(tmp, false)).isEmpty()) { + Item first = set.first(); + + if (tmp.start + tmp.delta == first.start) { + if (ref != tmp) { + tmp.delta += first.delta; + + set.pollFirst(); // Merge and remove obsolete head. + } + else { + tmp = first; + + first.start = start; + first.delta += delta; + } + } + } + + if (tmp != ref) + return true; + + return offer(new Item(start, delta)); // backup node with gaps + } + + while (true) { + boolean res = cntr.compareAndSet(cur, next = start + delta); + + assert res; + + Item peek = peek(); + + if (peek == null || peek.start != next) + return true; + + Item item = poll(); + + assert peek == item; + + start = item.start; + delta = item.delta; + cur = next; + } + } + + /** {@inheritDoc} */ + @Override public void updateInitial(long start, long delta) { + long cntr0 = get(); + + assert start >= cntr0 : "Illegal update counters order: cur=" + cntr0 + ", new=" + start; + + update(start, delta); + + initCntr = get(); + } + + /** */ + private Item poll() { + return queue.pollFirst(); + } + + /** */ + private Item peek() { + return queue.isEmpty() ? null : queue.first(); + } + + /** + * @param item Item. + */ + private boolean offer(Item item) { + if (queue.size() == MAX_MISSED_UPDATES) // Should trigger failure handler. + throw new IgniteException("Too many gaps [cntr=" + this + ']'); + + return queue.add(item); + } + + /** {@inheritDoc} */ + @Override public synchronized GridLongList finalizeUpdateCounters() { + Item item = poll(); + + GridLongList gaps = null; + + while (item != null) { + if (gaps == null) + gaps = new GridLongList((queue.size() + 1) * 2); + + long start = cntr.get() + 1; + long end = item.start; + + gaps.add(start); + gaps.add(end); + + // Close pending ranges. + cntr.set(item.start + item.delta); + + item = poll(); + } + + return gaps; + } + + /** {@inheritDoc} */ + @Override public long reserve(long delta) { + long cntr = get(); + + long reserved = reserveCntr.getAndAdd(delta); + + assert reserved >= cntr : "LWM after HWM: lwm=" + cntr + ", hwm=" + reserved; + + return reserved; + } + + /** {@inheritDoc} */ + @Override public long next(long delta) { + return cntr.getAndAdd(delta); + } + + /** {@inheritDoc} */ + @Override public synchronized boolean sequential() { + return gaps().isEmpty(); + } + + /** {@inheritDoc} */ + @Override public synchronized @Nullable byte[] getBytes() { + if (queue.isEmpty()) + return null; + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + DataOutputStream dos = new DataOutputStream(bos); + + dos.writeByte(VERSION); + + int size = queue.size(); + + dos.writeInt(size); + + for (Item item : queue) { + dos.writeLong(item.start); + dos.writeLong(item.delta); + } + + bos.close(); + + return bos.toByteArray(); + } + catch (IOException e) { + throw new IgniteException(e); + } + } + + /** + * @param raw Raw bytes. + */ + private @Nullable TreeSet fromBytes(@Nullable byte[] raw) { + if (raw == null) + return new TreeSet<>(); + + TreeSet ret = new TreeSet<>(); + + try { + ByteArrayInputStream bis = new ByteArrayInputStream(raw); + + DataInputStream dis = new DataInputStream(bis); + + dis.readByte(); // Version. + + int cnt = dis.readInt(); // Holes count. + + while(cnt-- > 0) + ret.add(new Item(dis.readLong(), dis.readLong())); + + return ret; + } + catch (IOException e) { + throw new IgniteException(e); + } + } + + /** */ + private TreeSet gaps() { + return queue; + } + + /** {@inheritDoc} */ + @Override public synchronized void reset() { + cntr.set(0); + + reserveCntr.set(0); + + queue = new TreeSet<>(); + } + + /** + * Update counter task. Update from start value by delta value. + */ + private static class Item implements Comparable { + /** */ + private long start; + + /** */ + private long delta; + + /** + * @param start Start value. + * @param delta Delta value. + */ + private Item(long start, long delta) { + this.start = start; + this.delta = delta; + } + + /** {@inheritDoc} */ + @Override public int compareTo(@NotNull Item o) { + return Long.compare(this.start, o.start); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Item [" + + "start=" + start + + ", delta=" + delta + + ']'; + } + + /** */ + public long start() { + return start; + } + + /** */ + public long delta() { + return delta; + } + + /** */ + public long absolute() { + return start + delta; + } + + /** */ + public boolean within(long cntr) { + return cntr - start < delta; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Item item = (Item)o; + + if (start != item.start) + return false; + + return (delta != item.delta); + } + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + PartitionTxUpdateCounterImpl cntr = (PartitionTxUpdateCounterImpl)o; + + if (!queue.equals(cntr.queue)) + return false; + + return this.cntr.get() == cntr.cntr.get(); + } + + /** {@inheritDoc} */ + @Override public long reserved() { + return reserveCntr.get(); + } + + /** {@inheritDoc} */ + @Override public synchronized boolean empty() { + return get() == 0 && sequential(); + } + + /** {@inheritDoc} */ + @Override public Iterator iterator() { + return F.iterator(queue.iterator(), item -> { + return new long[] {item.start, item.delta}; + }, true); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Counter [lwm=" + get() + ", holes=" + queue + + ", maxApplied=" + highestAppliedCounter() + ", hwm=" + reserveCntr.get() + ']'; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java old mode 100644 new mode 100755 index 39d8d5f..64aff27 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionUpdateCounter.java @@ -17,219 +17,116 @@ package org.apache.ignite.internal.processors.cache; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.ignite.IgniteLogger; +import java.util.Iterator; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.util.GridLongList; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** - * Partition update counter with MVCC delta updates capabilities. + * Partition update counter maintains three entities for tracking partition update state. +

    + *
  1. Low water mark (LWM) or update counter - lowest applied sequential update number.
  2. + *
  3. High water mark (HWM) or reservation counter - highest seen but unapplied yet update number.
  4. + *
  5. Out-of-order applied updates in range between LWM and HWM.
  6. + *
*/ -public class PartitionUpdateCounter { - /** */ - private IgniteLogger log; - - /** Queue of counter update tasks*/ - private final TreeSet queue = new TreeSet<>(); - - /** Counter. */ - private final AtomicLong cntr = new AtomicLong(); - - /** Initial counter. */ - private long initCntr; - +public interface PartitionUpdateCounter extends Iterable { /** - * @param log Logger. + * Restores update counter state. + * + * @param initUpdCntr LWM. + * @param cntrUpdData Counter updates raw data. */ - PartitionUpdateCounter(IgniteLogger log) { - this.log = log; - } + public void init(long initUpdCntr, @Nullable byte[] cntrUpdData); /** - * Sets init counter. - * - * @param updateCntr Init counter valus. + * @deprecated TODO LWM should be used as initial counter https://ggsystems.atlassian.net/browse/GG-17396 */ - public void init(long updateCntr) { - initCntr = updateCntr; + public long initial(); - cntr.set(updateCntr); - } + /** + * Get LWM. + */ + public long get(); /** - * @return Initial counter value. + * Increment LWM by 1. + * + * @return New LWM. */ - public long initial() { - return initCntr; - } + public long next(); /** - * @return Current update counter value. + * Increment LWM by delta. + * + * @param delta Delta. */ - public long get() { - return cntr.get(); - } + public long next(long delta); /** - * Adds delta to current counter value. + * Increment HWM by delta. * * @param delta Delta. - * @return Value before add. + * @return New HWM. */ - public long getAndAdd(long delta) { - return cntr.getAndAdd(delta); - } + public long reserve(long delta); /** - * @return Next update counter. + * Returns HWM. */ - public long next() { - return cntr.incrementAndGet(); - } + public long reserved(); /** - * Sets value to update counter, + * Sets update counter to absolute value. All missed updates will be discarded. * - * @param val Values. + * @param val Absolute value. + * @throws IgniteCheckedException if counter cannot be set to passed value due to incompatibility with current state. */ - public void update(long val) { - while (true) { - long val0 = cntr.get(); - - if (val0 >= val) - break; - - if (cntr.compareAndSet(val0, val)) - break; - } - } + public void update(long val) throws IgniteCheckedException; /** - * Updates counter by delta from start position. + * Applies counter update out of range. Update ranges must not intersect. * - * @param start Start. + * @param start Start (<= lwm). * @param delta Delta. + * @return {@code True} if update was actually applied. */ - public synchronized void update(long start, long delta) { - long cur = cntr.get(), next; - - if (cur > start) { - log.warning("Stale update counter task [cur=" + cur + ", start=" + start + ", delta=" + delta + ']'); - - return; - } - - if (cur < start) { - // backup node with gaps - offer(new Item(start, delta)); - - return; - } - - while (true) { - boolean res = cntr.compareAndSet(cur, next = start + delta); - - assert res; - - Item peek = peek(); - - if (peek == null || peek.start != next) - return; - - Item item = poll(); - - assert peek == item; - - start = item.start; - delta = item.delta; - cur = next; - } - } + public boolean update(long start, long delta); /** - * @param cntr Sets initial counter. + * Reset counter internal state to zero. */ - public void updateInitial(long cntr) { - if (get() < cntr) - update(cntr); - - initCntr = cntr; - } + public void reset(); /** - * @return Retrieves the minimum update counter task from queue. + * @param start Counter. + * @param delta Delta. + * @deprecated TODO https://ggsystems.atlassian.net/browse/GG-17396 */ - private Item poll() { - return queue.pollFirst(); - } + public void updateInitial(long start, long delta); /** - * @return Checks the minimum update counter task from queue. + * Flushes pending update counters closing all possible gaps. + * + * @return Even-length array of pairs [start, end] for each gap. */ - private Item peek() { - return queue.isEmpty() ? null : queue.first(); + public GridLongList finalizeUpdateCounters(); - } + /** */ + public @Nullable byte[] getBytes(); /** - * @param item Adds update task to priority queue. + * @return {@code True} if counter has no missed updates. */ - private void offer(Item item) { - queue.add(item); - } + public boolean sequential(); /** - * Flushes pending update counters closing all possible gaps. - * - * @return Even-length array of pairs [start, end] for each gap. + * @return {@code True} if counter has not seen any update. */ - public synchronized GridLongList finalizeUpdateCounters() { - Item item = poll(); - - GridLongList gaps = null; - - while (item != null) { - if (gaps == null) - gaps = new GridLongList((queue.size() + 1) * 2); - - long start = cntr.get() + 1; - long end = item.start; - - gaps.add(start); - gaps.add(end); - - // Close pending ranges. - update(item.start + item.delta); - - item = poll(); - } - - return gaps; - } + public boolean empty(); /** - * Update counter task. Update from start value by delta value. + * @return Iterator for pairs [start, delta] for each out-of-order update in the update counter sequence. */ - private static class Item implements Comparable { - /** */ - private final long start; - - /** */ - private final long delta; - - /** - * @param start Start value. - * @param delta Delta value. - */ - private Item(long start, long delta) { - this.start = start; - this.delta = delta; - } - - /** {@inheritDoc} */ - @Override public int compareTo(@NotNull Item o) { - return Long.compare(this.start, o.start); - } - } + @Override public Iterator iterator(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java index 9d962db..335caf3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java @@ -417,7 +417,7 @@ public class WalStateManager extends GridCacheSharedManagerAdapter { if (hasNonEmptyOwning) break; - if (locPart.updateCounter() > 0) { + if (!locPart.isEmpty()) { hasNonEmptyOwning = true; break; @@ -435,9 +435,8 @@ public class WalStateManager extends GridCacheSharedManagerAdapter { ", grpId=" + grp.groupId() + ", hasOwning=" + hasOwning + ", hasMoving=" + hasMoving + ", WALState=" + grp.walEnabled() + ", parts=" + parts); - if (hasOwning && !grp.localWalEnabled()) { + if (hasOwning && !grp.localWalEnabled()) grpsToEnableWal.add(grp.groupId()); - } else if (hasMoving && !hasOwning && grp.localWalEnabled()) { grpsToDisableWal.add(grp.groupId()); @@ -498,10 +497,13 @@ public class WalStateManager extends GridCacheSharedManagerAdapter { tmpDisabledWal = null; } + // Pending updates in groups with disabled WAL are not protected from crash. + // Need to trigger checkpoint for attempt to persist them. CheckpointFuture cpFut = triggerCheckpoint("wal-local-state-changed-rebalance-finished-" + topVer); assert cpFut != null; + // It's safe to switch partitions to owning state only if checkpoint was successfully finished. cpFut.finishFuture().listen(new IgniteInClosureX() { @Override public void applyx(IgniteInternalFuture future) { for (Integer grpId0 : session0.disabledGrps) { @@ -511,12 +513,12 @@ public class WalStateManager extends GridCacheSharedManagerAdapter { grp.topology().ownMoving(topVer); else if (log.isDebugEnabled()) log.debug("Cache group was destroyed before checkpoint finished, [grpId=" + grpId0 + ']'); - } if (log.isDebugEnabled()) log.debug("Refresh partitions due to rebalance finished"); + // Trigger exchange for switching to ideal assignment when all nodes are ready. cctx.exchange().refreshPartitions(); } }); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java index 3e68306..22e3dd5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java @@ -915,12 +915,11 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter TxCounters counters = txCounters(false); if (counters != null) - cctx.tm().txHandler().applyPartitionsUpdatesCounters(counters.updateCounters()); + cctx.tm().txHandler().applyPartitionsUpdatesCounters(counters.updateCounters(), true, false); state(ROLLED_BACK); cctx.mvccCaching().onTxFinished(this, false); - } } catch (IgniteCheckedException | RuntimeException | Error e) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java index a1eb01c..584ede2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java @@ -47,6 +47,7 @@ import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.C1; 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.S; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteClosure; @@ -98,8 +99,33 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry { /** {@inheritDoc} */ @Override protected long nextPartitionCounter(AffinityTopologyVersion topVer, boolean primary, + boolean init, @Nullable Long primaryCntr) { - return locPart.nextUpdateCounter(cctx.cacheId(), topVer, primary, primaryCntr); + try { + return locPart.nextUpdateCounter(cctx.cacheId(), topVer, primary, init, primaryCntr); + } + catch (Throwable t) { + log.error("Failed to update counter for atomic cache [" + + ", initial=" + init + + ", primaryCntr=" + primaryCntr + + ", part=" + locPart + ']', t); + + throw t; + } + } + + /** {@inheritDoc} */ + @Override protected long nextPartitionCounter(IgniteInternalTx tx, @Nullable Long primaryCntr) { + try { + return locPart.nextUpdateCounter(cctx.cacheId(), tx, primaryCntr); + } + catch (Throwable t) { + log.error("Failed to update counter for tx cache [" + + ", primaryCntr=" + primaryCntr + + ", part=" + locPart + ", tx=" + CU.txString(tx) + ']', t); + + throw t; + } } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java index b00ad56..dc29ebe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.cache.distributed.dht; -import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.UUID; @@ -38,7 +37,6 @@ import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTx import org.apache.ignite.internal.processors.cache.mvcc.MvccFuture; import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; -import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -437,11 +435,6 @@ public final class GridDhtTxFinishFuture extends GridCacheCompoundIdentity add(fut); // Append new future. - Collection updCntrs = new ArrayList<>(dhtMapping.entries().size()); - - for (IgniteTxEntry e : dhtMapping.entries()) - updCntrs.add(e.updateCounter()); - GridDhtTxFinishRequest req = new GridDhtTxFinishRequest( tx.nearNodeId(), futId, @@ -465,7 +458,7 @@ public final class GridDhtTxFinishFuture extends GridCacheCompoundIdentity tx.subjectId(), tx.taskNameHash(), tx.activeCachesDeploymentEnabled(), - updCntrs, + null, false, false, mvccSnapshot, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishRequest.java index 04f411d..9498e32 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishRequest.java @@ -257,13 +257,6 @@ public class GridDhtTxFinishRequest extends GridDistributedTxFinishRequest { waitRemoteTxs, mvccSnapshot, updCntrs); - - if (updateIdxs != null && !updateIdxs.isEmpty()) { - partUpdateCnt = new GridLongList(updateIdxs.size()); - - for (Long idx : updateIdxs) - partUpdateCnt.add(idx); - } } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java index fb485a5..83edb29 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java @@ -71,6 +71,7 @@ import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxState; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; +import org.apache.ignite.internal.processors.cache.transactions.TxCounters; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.dr.GridDrType; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; @@ -1258,6 +1259,8 @@ public final class GridDhtTxPrepareFuture extends GridCacheCompoundFuture counters; + /** */ public PartitionUpdateCountersMessage() { // No-op. @@ -145,6 +151,24 @@ public class PartitionUpdateCountersMessage implements Message { } /** + * Calculate next counter for partition. + * + * @param partId Partition id. + * + * @return Next counter for partition. + */ + public Long nextCounter(int partId) { + if (counters == null) { + counters = U.newHashMap(size); + + for (int i = 0; i < size; i++) + counters.put(partition(i), initialCounter(i)); + } + + return counters.computeIfPresent(partId, (key, cntr) -> cntr + 1); + } + + /** * Clears message. */ public void clear() { 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 93602db..803681f 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,8 +1025,10 @@ public class GridDhtPartitionDemander { try { cached = cctx.cache().entryEx(entry.key(), topVer); - if (log.isTraceEnabled()) - log.trace("Rebalancing key [key=" + entry.key() + ", part=" + p + ", node=" + from.id() + ']'); + if (log.isTraceEnabled()) { + log.trace("Rebalancing key [key=" + entry.key() + ", part=" + p + ", fromNode=" + + from.id() + ", grpId=" + grp.groupId() + ']'); + } if (preloadPred == null || preloadPred.apply(entry)) { if (cached.initialValue( diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java index 7f52856..a216a16 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java @@ -445,6 +445,15 @@ class GridDhtPartitionSupplier { log.info("Finished supplying rebalancing [" + supplyRoutineInfo(topicId, nodeId, demandMsg) + "]"); } catch (Throwable t) { + if (iter != null && !iter.isClosed()) { + try { + iter.close(); + } + catch (IgniteCheckedException e) { + t.addSuppressed(e); + } + } + if (grp.shared().kernalContext().isStopping()) return; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index 0ec1b7c..b247cd2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -297,7 +297,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte @GridToStringExclude private volatile IgniteDhtPartitionHistorySuppliersMap partHistSuppliers = new IgniteDhtPartitionHistorySuppliersMap(); - /** */ + /** Reserved max available history for calculation of history supplier on coordinator. */ private volatile Map> partHistReserved; /** */ @@ -354,6 +354,9 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte /** Discovery lag / Clocks discrepancy, calculated on coordinator when all single messages are received. */ private T2 discoveryLag; + /** TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11799 */ + private Map> clearingPartitions; + /** * @param cctx Cache context. * @param busyLock Busy lock. @@ -1053,6 +1056,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte clientTop.fullUpdateCounters(), Collections.emptySet(), null, + null, null); } finally { @@ -1436,6 +1440,8 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte cctx.exchange().exchangerBlockingSectionEnd(); } + clearingPartitions = new HashMap(); + timeBag.finishGlobalStage("WAL history reservation"); // Skipping wait on local join is available when all cluster nodes have the same protocol. @@ -1674,7 +1680,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte cctx.exchange().exchangerBlockingSectionBegin(); try { - // This avoids unnessesary waiting for rollback. + // This avoids unnecessary waiting for rollback. partReleaseFut.get(curTimeout > 0 && !txRolledBack ? Math.min(curTimeout, waitTimeout) : waitTimeout, TimeUnit.MILLISECONDS); @@ -3119,10 +3125,10 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte continue; if (localReserved != null) { - Long localCntr = localReserved.get(p); + Long localHistCntr = localReserved.get(p); - if (localCntr != null && localCntr <= minCntr && maxCntrObj.nodes.contains(cctx.localNodeId())) { - partHistSuppliers.put(cctx.localNodeId(), top.groupId(), p, localCntr); + if (localHistCntr != null && localHistCntr <= minCntr && maxCntrObj.nodes.contains(cctx.localNodeId())) { + partHistSuppliers.put(cctx.localNodeId(), top.groupId(), p, localHistCntr); haveHistory.add(p); @@ -3153,7 +3159,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte top.globalPartSizes(partSizes); - Map> partitionsToRebalance = top.resetOwners(ownersByUpdCounters, haveHistory); + Map> partitionsToRebalance = top.resetOwners(ownersByUpdCounters, haveHistory, this); for (Map.Entry> e : partitionsToRebalance.entrySet()) { UUID nodeId = e.getKey(); @@ -3457,13 +3463,8 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte && ((SnapshotDiscoveryMessage)discoveryCustomMessage).needAssignPartitions()) assignPartitionsStates(); } - else { - if (exchCtx.events().hasServerJoin()) - assignPartitionsStates(); - - if (exchCtx.events().hasServerLeft()) - detectLostPartitions(resTopVer); - } + else if (exchCtx.events().hasServerJoin()) + assignPartitionsStates(); // Recalculate new affinity based on partitions availability. if (!exchCtx.mergeExchanges() && forceAffReassignment) { @@ -3488,6 +3489,12 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte GridDhtPartitionsFullMessage msg = createPartitionsMessage(true, minVer.compareToIgnoreTimestamp(PARTIAL_COUNTERS_MAP_SINCE) >= 0); + // Lost partition detection should be done after full message is prepared otherwise in case of IGNORE policy + // lost partitions will be moved to OWNING state and after what send to other nodes resulting in + // wrong lost state calculation (another possibility to consider - calculate lost state only on coordinator). + if (firstDiscoEvt.type() != EVT_DISCOVERY_CUSTOM_EVT && exchCtx.events().hasServerLeft()) + detectLostPartitions(resTopVer); + if (exchCtx.mergeExchanges()) { assert !centralizedAff; @@ -3776,7 +3783,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte int parallelismLvl = U.availableThreadCount(cctx.kernalContext(), GridIoPolicy.SYSTEM_POOL, 2); try { - U.doInParallel( + U.doInParallelUninterruptibly( parallelismLvl, cctx.kernalContext().getSystemExecutorService(), nonLocalCacheGroups(), @@ -4220,7 +4227,8 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte cntrMap, msg.partsToReload(cctx.localNodeId(), grpId), partsSizes.getOrDefault(grpId, Collections.emptyMap()), - null); + null, + this); } else { GridDhtPartitionTopology top = cctx.exchange().clientTopology(grpId, events().discoveryCache()); @@ -4233,7 +4241,8 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte cntrMap, Collections.emptySet(), null, - null); + null, + this); } return null; @@ -5018,6 +5027,40 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte } /** + * If partition is clearing or already cleared we need full rebalance even if supplier is exists. + * (it still could be used by other demanders) + * + * @param grp Group. + * @param part Partition. + */ + public boolean isClearingPartition(CacheGroupContext grp, int part) { + if (!grp.persistenceEnabled()) + return false; + + synchronized (mux) { + if (clearingPartitions == null) + return false; + + Set parts = clearingPartitions.get(grp.groupId()); + + return parts != null && parts.contains(part); + } + } + + /** + * @param grp Group. + * @param part Partition. + */ + public void addClearingPartition(CacheGroupContext grp, int part) { + if (!grp.persistenceEnabled()) + return; + + synchronized (mux) { + clearingPartitions.computeIfAbsent(grp.groupId(), k -> new HashSet()).add(part); + } + } + + /** * */ private static class FinishState { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java index ff420a7..8ecb147 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java @@ -253,6 +253,10 @@ public class GridDhtPreloader extends GridCachePreloaderAdapter { if (part.state() == RENTING) { if (part.reserve()) { part.moving(); + + if (exchFut != null) + exchFut.addClearingPartition(grp, part.id()); + part.clearAsync(); part.release(); @@ -277,7 +281,8 @@ public class GridDhtPreloader extends GridCachePreloaderAdapter { histSupplier = ctx.discovery().node(nodeId); } - if (histSupplier != null) { + // Clearing partition should always be fully reloaded. + if (histSupplier != null && !exchFut.isClearingPartition(grp, p)) { assert grp.persistenceEnabled(); assert remoteOwners(p, topVer).contains(histSupplier) : remoteOwners(p, topVer); @@ -291,6 +296,7 @@ public class GridDhtPreloader extends GridCachePreloaderAdapter { ); } + // TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11790 msg.partitions().addHistorical(p, part.initialUpdateCounter(), countersMap.updateCounter(p), partitions); } else { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloaderAssignments.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloaderAssignments.java index 6f98889..8783c73 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloaderAssignments.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloaderAssignments.java @@ -81,7 +81,6 @@ public class GridDhtPreloaderAssignments extends ConcurrentHashMap full; public IgniteDhtDemandedPartitionsMap( @@ -47,6 +49,7 @@ public class IgniteDhtDemandedPartitionsMap implements Serializable { } public IgniteDhtDemandedPartitionsMap() { + // No-op. } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java index 0298d31..8a8d7d0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java @@ -729,7 +729,8 @@ public class GridClientPartitionTopology implements GridDhtPartitionTopology { @Nullable CachePartitionFullCountersMap cntrMap, Set partsToReload, @Nullable Map partSizes, - @Nullable AffinityTopologyVersion msgTopVer) { + @Nullable AffinityTopologyVersion msgTopVer, + @Nullable GridDhtPartitionsExchangeFuture exchFut) { if (log.isDebugEnabled()) log.debug("Updating full partition map [exchVer=" + exchangeVer + ", parts=" + fullMapString() + ']'); @@ -1162,7 +1163,9 @@ public class GridClientPartitionTopology implements GridDhtPartitionTopology { } /** {@inheritDoc} */ - @Override public Map> resetOwners(Map> ownersByUpdCounters, Set haveHistory) { + @Override public Map> resetOwners(Map> ownersByUpdCounters, + Set haveHistory, + GridDhtPartitionsExchangeFuture exchFut) { Map> result = new HashMap<>(); lock.writeLock().lock(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java index c1f742e..a131a21 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java @@ -53,12 +53,15 @@ import org.apache.ignite.internal.processors.cache.distributed.dht.GridReservabl import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPreloader; import org.apache.ignite.internal.processors.cache.extras.GridCacheObsoleteEntryExtras; import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; +import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; +import org.apache.ignite.internal.processors.cache.transactions.TxCounters; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.GridQueryRowCacheCleaner; import org.apache.ignite.internal.util.GridLongList; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.lang.GridIterator; import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteInClosure; @@ -218,7 +221,7 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements // Log partition creation for further crash recovery purposes. if (grp.walEnabled() && !recovery) - ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, state(), updateCounter())); + ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, state(), 0)); // Inject row cache cleaner on store creation // Used in case the cache with enabled SqlOnheapCache is single cache at the cache group @@ -396,9 +399,21 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements } /** - * + * TODO FIXME Get rid of deferred delete queue https://issues.apache.org/jira/browse/IGNITE-11704 */ public void cleanupRemoveQueue() { + if (state() == MOVING) { + if (rmvQueue.sizex() >= rmvQueueMaxSize) { + LT.warn(log, "Deletion queue cleanup for moving partition was delayed until rebalance is finished. " + + "[grpId=" + this.grp.groupId() + + ", partId=" + id() + + ", grpParts=" + this.grp.affinity().partitions() + + ", maxRmvQueueSize=" + rmvQueueMaxSize + ']'); + } + + return; + } + while (rmvQueue.sizex() >= rmvQueueMaxSize) { RemovedEntryHolder item = rmvQueue.pollFirst(); @@ -535,7 +550,7 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements this.state.compareAndSet(state0, setPartState(state0, toState)); try { - ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, toState, updateCounter())); + ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, toState, 0)); } catch (IgniteCheckedException e) { U.error(log, "Error while writing to log", e); @@ -560,7 +575,7 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements if (update) { try { - ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, toState, updateCounter())); + ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, toState, 0)); } catch (IgniteCheckedException e) { U.error(log, "Failed to log partition state change to WAL.", e); @@ -717,7 +732,7 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements } } - ctx.evict().evictPartitionAsync(grp,this); + ctx.evict().evictPartitionAsync(grp, this); } /** @@ -970,40 +985,82 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements } /** + * Returns new update counter for primary node or passed counter for backup node. + *

+ * Used for non-tx cases. + *

+ * Counter generation/update logic is delegated to counter implementation. + * * @param cacheId ID of cache initiated counter update. * @param topVer Topology version for current operation. + * @param init {@code True} if initial update. * @return Next update index. */ - public long nextUpdateCounter(int cacheId, AffinityTopologyVersion topVer, boolean primary, @Nullable Long primaryCntr) { - long nextCntr = store.nextUpdateCounter(); + public long nextUpdateCounter(int cacheId, AffinityTopologyVersion topVer, boolean primary, boolean init, + @Nullable Long primaryCntr) { + long nextCntr; + + if (primaryCntr == null) // Primary node. + nextCntr = store.nextUpdateCounter(); + else { + assert !init : "Initial update must generate a counter for partition " + this; + + // Backup. + assert primaryCntr != 0; + + store.updateCounter(nextCntr = primaryCntr); + } if (grp.sharedGroup()) - grp.onPartitionCounterUpdate(cacheId, id, primaryCntr != null ? primaryCntr : nextCntr, topVer, primary); + grp.onPartitionCounterUpdate(cacheId, id, nextCntr, topVer, primary); - // This is first update in partition, we should log partition state information for further crash recovery. - if (nextCntr == 1) { - if (grp.persistenceEnabled() && grp.walEnabled()) - try { - ctx.wal().log(new PartitionMetaStateRecord(grp.groupId(), id, state(), 0)); - } - catch (IgniteCheckedException e) { - U.error(log, "Failed to log partition state snapshot to WAL.", e); + return nextCntr; + } - ctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); - } + /** + * Used for transactions. + * + * @param cacheId Cache id. + * @param tx Tx. + * @param primaryCntr Primary counter. + */ + public long nextUpdateCounter(int cacheId, IgniteInternalTx tx, @Nullable Long primaryCntr) { + Long nextCntr; + + if (primaryCntr != null) + nextCntr = primaryCntr; + else { + TxCounters txCounters = tx.txCounters(false); + + assert txCounters != null : "Must have counters for tx [nearXidVer=" + tx.nearXidVersion() + ']'; + + // Null must never be returned on primary node. + nextCntr = txCounters.generateNextCounter(cacheId, id()); + + assert nextCntr != null : this; } + if (grp.sharedGroup()) + grp.onPartitionCounterUpdate(cacheId, id, nextCntr, tx.topologyVersion(), tx.local()); + return nextCntr; } /** - * @return Current update counter. + * @return Current update counter (LWM). */ public long updateCounter() { return store.updateCounter(); } /** + * @return Current reserved counter (HWM). + */ + public long reservedCounter() { + return store.reservedCounter(); + } + + /** * @param val Update counter value. */ public void updateCounter(long val) { @@ -1018,14 +1075,7 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements } /** - * @param val Initial update counter value. - */ - public void initialUpdateCounter(long val) { - store.updateInitialCounter(val); - } - - /** - * Updates MVCC cache update counter on primary node. + * Increments cache update counter on primary node. * * @param delta Value to be added to update counter. * @return Update counter value before update. @@ -1040,8 +1090,15 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements * @param start Start position * @param delta Delta. */ - public void updateCounter(long start, long delta) { - store.updateCounter(start, delta); + public boolean updateCounter(long start, long delta) { + return store.updateCounter(start, delta); + } + + /** + * Reset partition counters. + */ + public void resetCounters() { + store.resetUpdateCounter(); } /** @@ -1086,7 +1143,8 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements try { CacheDataRow row = it0.next(); - // Do not clear fresh rows in case of single partition clearing. + // Do not clear fresh rows in case of partition reloading. + // This is required because updates are possible to moving partition which is currently cleared. if (row.version().compareTo(clearVer) >= 0 && (state() == MOVING && clear)) continue; @@ -1256,7 +1314,8 @@ public class GridDhtLocalPartition extends GridCacheConcurrentMapImpl implements "state", state(), "reservations", reservations(), "empty", isEmpty(), - "createTime", U.format(createTime)); + "createTime", U.format(createTime), + "cntr", dataStore().partUpdateCounter()); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java index 7b9c3c3..f907bf2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java @@ -292,6 +292,7 @@ public interface GridDhtPartitionTopology { * @param partsToReload Set of partitions that need to be reloaded. * @param msgTopVer Topology version from incoming message. This value is not null only for case message is not * related to exchange. Value should be not less than previous 'Topology version from exchange'. + * @param exchFut Future which is not null for initial partition update on exchange. * @return {@code True} if local state was changed. */ public boolean update( @@ -300,7 +301,9 @@ public interface GridDhtPartitionTopology { @Nullable CachePartitionFullCountersMap cntrMap, Set partsToReload, @Nullable Map partSizes, - @Nullable AffinityTopologyVersion msgTopVer); + @Nullable AffinityTopologyVersion msgTopVer, + @Nullable GridDhtPartitionsExchangeFuture exchFut + ); /** * @param exchId Exchange ID. @@ -359,7 +362,7 @@ public interface GridDhtPartitionTopology { public CachePartitionFullCountersMap fullUpdateCounters(); /** - * @param skipZeros {@code True} for adding zero counter to map. + * @param skipZeros {@code True} to exclude zero counters from map. * @return Partition update counters. */ public CachePartitionPartialCountersMap localUpdateCounters(boolean skipZeros); @@ -420,13 +423,16 @@ public interface GridDhtPartitionTopology { /** * Calculates nodes and partitions which have non-actual state and must be rebalanced. * State of all current owners that aren't contained in the given {@code ownersByUpdCounters} will be reset to MOVING. + * Called on coordinator during assignment of partition states. * * @param ownersByUpdCounters Map (partition, set of node IDs that have most actual state about partition * (update counter is maximal) and should hold OWNING state for such partition). * @param haveHistory Set of partitions which have WAL history to rebalance. + * @param exchFut Exchange future for operation. * @return Map (nodeId, set of partitions that should be rebalanced fully by this node). */ - public Map> resetOwners(Map> ownersByUpdCounters, Set haveHistory); + public Map> resetOwners(Map> ownersByUpdCounters, Set haveHistory, + GridDhtPartitionsExchangeFuture exchFut); /** * Callback on exchange done. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java index 026a54f..b6b84d5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java @@ -42,6 +42,7 @@ import org.apache.ignite.events.EventType; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.managers.discovery.DiscoCache; +import org.apache.ignite.internal.pagemem.wal.record.RollbackRecord; import org.apache.ignite.internal.processors.affinity.AffinityAssignment; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheGroupContext; @@ -428,7 +429,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { } } else - createPartitions(affVer, affAssignment, updateSeq); + createPartitions(affVer, affAssignment, updateSeq, exchFut); } else { // If preloader is disabled, then we simply clear out @@ -478,8 +479,10 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { * @param affVer Affinity version. * @param aff Affinity assignments. * @param updateSeq Update sequence. + * @param exchFut */ - private void createPartitions(AffinityTopologyVersion affVer, List> aff, long updateSeq) { + private void createPartitions(AffinityTopologyVersion affVer, List> aff, long updateSeq, + GridDhtPartitionsExchangeFuture exchFut) { if (!grp.affinityNode()) return; @@ -493,8 +496,13 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (localNode(p, aff)) { // This will make sure that all non-existing partitions // will be created in MOVING state. + boolean existing = locParts.get(p) != null; + GridDhtLocalPartition locPart = getOrCreatePartition(p); + if (existing && locPart.state() == MOVING && !locPart.isEmpty()) + exchFut.addClearingPartition(grp, p); + updateSeq = updateLocal(p, locPart.state(), updateSeq, affVer); } } @@ -758,7 +766,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (partitionLocalNode(p, topVer)) { // Prepare partition to rebalance if it's not happened on full map update phase. if (locPart == null || locPart.state() == RENTING || locPart.state() == EVICTED) - locPart = rebalancePartition(p, false); + locPart = rebalancePartition(p, true, exchFut); GridDhtPartitionState state = locPart.state(); @@ -772,6 +780,9 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { log.debug("Will not own partition (there are owners to rebalance from) " + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", owners = " + owners + ']'); } + + if (exchFut.isClearingPartition(grp, p)) + locPart.clearAsync(); } else updateSeq = updateLocal(p, locPart.state(), updateSeq, topVer); @@ -1359,8 +1370,9 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { */ private boolean shouldOverridePartitionMap(GridDhtPartitionMap currentMap, GridDhtPartitionMap newMap) { return newMap != null && - (newMap.topologyVersion().compareTo(currentMap.topologyVersion()) > 0 || - newMap.topologyVersion().compareTo(currentMap.topologyVersion()) == 0 && newMap.updateSequence() > currentMap.updateSequence()); + (newMap.topologyVersion().compareTo(currentMap.topologyVersion()) > 0 || + newMap.topologyVersion().compareTo(currentMap.topologyVersion()) == 0 && + newMap.updateSequence() > currentMap.updateSequence()); } /** {@inheritDoc} */ @@ -1370,7 +1382,8 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { @Nullable CachePartitionFullCountersMap incomeCntrMap, Set partsToReload, @Nullable Map partSizes, - @Nullable AffinityTopologyVersion msgTopVer) { + @Nullable AffinityTopologyVersion msgTopVer, + @Nullable GridDhtPartitionsExchangeFuture exchFut) { if (log.isDebugEnabled()) { log.debug("Updating full partition map " + "[grp=" + grp.cacheOrGroupName() + ", exchVer=" + exchangeVer + ", fullMap=" + fullMapString() + ']'); @@ -1408,17 +1421,21 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { long updCntr = incomeCntrMap.updateCounter(part.id()); long curCntr = part.updateCounter(); - if (updCntr != 0 && updCntr > curCntr) { + // Avoid zero counter update to empty partition to prevent lazy init. + if (updCntr != 0 || curCntr != 0) { part.updateCounter(updCntr); - if (log.isDebugEnabled()) - log.debug("Partition update counter has updated [grp=" + grp.cacheOrGroupName() + ", p=" + part.id() - + ", state=" + part.state() + ", prevCntr=" + curCntr + ", nextCntr=" + updCntr + "]"); + if (updCntr > curCntr) { + if (log.isDebugEnabled()) + log.debug("Partition update counter has updated [grp=" + grp.cacheOrGroupName() + ", p=" + part.id() + + ", state=" + part.state() + ", prevCntr=" + curCntr + ", nextCntr=" + updCntr + "]"); + } } } } } + // TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11800 if (exchangeVer != null) { // Ignore if exchange already finished or new exchange started. if (readyTopVer.compareTo(exchangeVer) > 0 || lastTopChangeVer.compareTo(exchangeVer) > 0) { @@ -1557,6 +1574,9 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { nodeMap != null && grp.persistenceEnabled() && readyTopVer.initialized()) { + + assert exchFut != null; + for (Map.Entry e : nodeMap.entrySet()) { int p = e.getKey(); GridDhtPartitionState state = e.getValue(); @@ -1575,9 +1595,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { } } else if (state == MOVING) { - boolean haveHistory = !partsToReload.contains(p); - - rebalancePartition(p, haveHistory); + rebalancePartition(p, partsToReload.contains(p), exchFut); changed = true; } @@ -1698,12 +1716,21 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { continue; long updCntr = cntrMap.updateCounter(part.id()); + long locUpdCntr = part.updateCounter(); - if (updCntr > part.updateCounter()) + if (updCntr != 0 || locUpdCntr != 0) { // Avoid creation of empty partition. part.updateCounter(updCntr); - else if (part.updateCounter() > 0) { + + if (updCntr > locUpdCntr) { + if (log.isDebugEnabled()) + log.debug("Partition update counter has updated [grp=" + grp.cacheOrGroupName() + ", p=" + part.id() + + ", state=" + part.state() + ", prevCntr=" + locUpdCntr + ", nextCntr=" + updCntr + "]"); + } + } + + if (locUpdCntr > updCntr) { cntrMap.initialUpdateCounter(part.id(), part.initialUpdateCounter()); - cntrMap.updateCounter(part.id(), part.updateCounter()); + cntrMap.updateCounter(part.id(), locUpdCntr); } } finally { @@ -2105,7 +2132,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (recentlyLost != null) { U.warn(log, "Detected lost partitions [grp=" + grp.cacheOrGroupName() + ", parts=" + S.compact(recentlyLost) - + ", plc=" + plc + "]"); + + ", plc=" + plc + ", topVer=" + resTopVer + "]"); } if (lostParts != null && plc != PartitionLossPolicy.IGNORE) @@ -2147,11 +2174,8 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (marked) { updateLocal(locPart.id(), locPart.state(), updSeq, resTopVer); - long updateCntr = locPart.updateCounter(); - - //Set update counters to 0, for full rebalance. - locPart.updateCounter(updateCntr, -updateCntr); - locPart.initialUpdateCounter(0); + // Reset counters to zero for triggering full rebalance. + locPart.resetCounters(); } } } @@ -2188,7 +2212,9 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { } /** {@inheritDoc} */ - @Override public Map> resetOwners(Map> ownersByUpdCounters, Set haveHistory) { + @Override public Map> resetOwners(Map> ownersByUpdCounters, + Set haveHistory, + GridDhtPartitionsExchangeFuture exchFut) { Map> result = new HashMap<>(); ctx.database().checkpointReadLock(); @@ -2208,10 +2234,9 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { continue; if (!newOwners.contains(ctx.localNodeId())) { - rebalancePartition(part, haveHistory.contains(part)); + rebalancePartition(part, !haveHistory.contains(part), exchFut); - result.computeIfAbsent(ctx.localNodeId(), n -> new HashSet<>()); - result.get(ctx.localNodeId()).add(part); + result.computeIfAbsent(ctx.localNodeId(), n -> new HashSet<>()).add(part); } } @@ -2237,8 +2262,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (partMap.nodeId().equals(ctx.localNodeId())) updateSeq.setIfGreater(partMap.updateSequence()); - result.computeIfAbsent(remoteNodeId, n -> new HashSet<>()); - result.get(remoteNodeId).add(part); + result.computeIfAbsent(remoteNodeId, n -> new HashSet<>()).add(part); } } } @@ -2247,6 +2271,10 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { UUID nodeId = entry.getKey(); Set rebalancedParts = entry.getValue(); + // Add to wait groups to ensure late assignment switch after all partitions are rebalanced. + for (Integer part : rebalancedParts) + ctx.cache().context().affinity().addToWaitGroup(groupId(), part, nodeId, topologyVersionFuture().initialVersion()); + if (!rebalancedParts.isEmpty()) { Set historical = rebalancedParts.stream() .filter(haveHistory::contains) @@ -2281,10 +2309,11 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { * Prevents ongoing renting if required. * * @param p Partition id. - * @param haveHistory If {@code true} there is WAL history to rebalance partition, - * in other case partition will be cleared for full rebalance. + * @param clear If {@code true} partition have to be cleared before rebalance. + * Required in case of full state transfer to handle removals on supplier. + * @param exchFut Future related to partition state change. */ - private GridDhtLocalPartition rebalancePartition(int p, boolean haveHistory) { + private GridDhtLocalPartition rebalancePartition(int p, boolean clear, GridDhtPartitionsExchangeFuture exchFut) { GridDhtLocalPartition part = getOrCreatePartition(p); // Prevent renting. @@ -2303,8 +2332,11 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { if (part.state() != MOVING) part.moving(); - if (!haveHistory) + if (clear) { + exchFut.addClearingPartition(grp, part.id()); + part.clearAsync(); + } assert part.state() == MOVING : part; @@ -2656,9 +2688,6 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { * Pre-processes partition update counters before exchange. */ @Override public void finalizeUpdateCounters() { - if (!grp.mvccEnabled()) - return; - // It is need to acquire checkpoint lock before topology lock acquiring. ctx.database().checkpointReadLock(); @@ -2680,6 +2709,25 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { GridLongList gaps = part.finalizeUpdateCounters(); if (gaps != null) { + for (int j = 0; j < gaps.size() / 2; j++) { + long gapStart = gaps.get(j * 2); + long gapStop = gaps.get(j * 2 + 1); + + if (part.group().persistenceEnabled() && + part.group().walEnabled() && + !part.group().mvccEnabled()) { + RollbackRecord rec = new RollbackRecord(part.group().groupId(), part.id(), + gapStart - 1, gapStop - gapStart + 1); + + try { + ctx.wal().log(rec); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + } + for (GridCacheContext ctx0 : grp.caches()) ctx0.continuousQueries().closeBackupUpdateCountersGaps(ctx0, part.id(), topVer, gaps); } @@ -2964,7 +3012,7 @@ public class GridDhtPartitionTopologyImpl implements GridDhtPartitionTopology { * Checks consistency after all operations. */ private void consistencyCheck() { - // no-op + // No-op. } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java index 404e194..c458d3e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java @@ -70,7 +70,7 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { private volatile boolean stop; /** Check stop eviction context. */ - private final EvictionContext sharedEvictionContext = () -> stop; + private final EvictionContext sharedEvictionCtx = () -> stop; /** Number of maximum concurrent operations. */ private volatile int threads; @@ -94,13 +94,13 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { * * @param grp Group context. */ - public void onCacheGroupStopped(CacheGroupContext grp){ - GroupEvictionContext groupEvictionContext = evictionGroupsMap.remove(grp.groupId()); + public void onCacheGroupStopped(CacheGroupContext grp){ + GroupEvictionContext grpEvictionCtx = evictionGroupsMap.remove(grp.groupId()); - if (groupEvictionContext != null){ - groupEvictionContext.stop(); + if (grpEvictionCtx != null){ + grpEvictionCtx.stop(); - groupEvictionContext.awaitFinishAll(); + grpEvictionCtx.awaitFinishAll(); } } @@ -111,23 +111,23 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { * @param part Partition to evict. */ public void evictPartitionAsync(CacheGroupContext grp, GridDhtLocalPartition part) { - GroupEvictionContext groupEvictionContext = evictionGroupsMap.computeIfAbsent( + GroupEvictionContext grpEvictionCtx = evictionGroupsMap.computeIfAbsent( grp.groupId(), (k) -> new GroupEvictionContext(grp)); // Check node stop. - if (groupEvictionContext.shouldStop()) + if (grpEvictionCtx.shouldStop()) return; int bucket; synchronized (mux) { - if (!groupEvictionContext.partIds.add(part.id())) + if (!grpEvictionCtx.partIds.add(part.id())) return; - bucket = evictionQueue.offer(new PartitionEvictionTask(part, groupEvictionContext)); + bucket = evictionQueue.offer(new PartitionEvictionTask(part, grpEvictionCtx)); } - groupEvictionContext.totalTasks.incrementAndGet(); + grpEvictionCtx.totalTasks.incrementAndGet(); if (log.isDebugEnabled()) log.debug("Partition has been scheduled for eviction [grp=" + grp.cacheOrGroupName() @@ -143,7 +143,7 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { */ private void scheduleNextPartitionEviction(int bucket) { // Check node stop. - if (sharedEvictionContext.shouldStop()) + if (sharedEvictionCtx.shouldStop()) return; synchronized (mux) { @@ -178,17 +178,17 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { // Print current eviction progress. showProgress(); - GroupEvictionContext groupEvictionContext = evictionTask.groupEvictionCtx; + GroupEvictionContext grpEvictionCtx = evictionTask.grpEvictionCtx; // Check that group or node stopping. - if (groupEvictionContext.shouldStop()) + if (grpEvictionCtx.shouldStop()) continue; // Get permit for this task. permits--; // Register task future, may need if group or node will be stopped. - groupEvictionContext.taskScheduled(evictionTask); + grpEvictionCtx.taskScheduled(evictionTask); evictionTask.finishFut.listen(f -> { synchronized (mux) { @@ -294,7 +294,7 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { /** {@inheritDoc} */ @Override public boolean shouldStop() { - return stop || sharedEvictionContext.shouldStop(); + return stop || sharedEvictionCtx.shouldStop(); } /** @@ -384,35 +384,35 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { private final long size; /** Eviction context. */ - private final GroupEvictionContext groupEvictionCtx; + private final GroupEvictionContext grpEvictionCtx; /** */ private final GridFutureAdapter finishFut = new GridFutureAdapter<>(); /** * @param part Partition. - * @param groupEvictionCtx Eviction context. + * @param grpEvictionCtx Eviction context. */ private PartitionEvictionTask( GridDhtLocalPartition part, - GroupEvictionContext groupEvictionCtx + GroupEvictionContext grpEvictionCtx ) { this.part = part; - this.groupEvictionCtx = groupEvictionCtx; + this.grpEvictionCtx = grpEvictionCtx; size = part.fullSize(); } /** {@inheritDoc} */ @Override public void run() { - if (groupEvictionCtx.shouldStop()) { + if (grpEvictionCtx.shouldStop()) { finishFut.onDone(); return; } try { - boolean success = part.tryClear(groupEvictionCtx); + boolean success = part.tryClear(grpEvictionCtx); if (success) { if (part.state() == GridDhtPartitionState.EVICTED && part.markForDestroy()) @@ -425,7 +425,7 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { // Re-offer partition if clear was unsuccessful due to partition reservation. if (!success) - evictPartitionAsync(groupEvictionCtx.grp, part); + evictPartitionAsync(grpEvictionCtx.grp, part); } catch (Throwable ex) { finishFut.onDone(ex); @@ -435,9 +435,8 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { false, true); } - else{ + else LT.error(log, ex, "Partition eviction failed, this can cause grid hang."); - } } } } @@ -523,9 +522,8 @@ public class PartitionsEvictManager extends GridCacheSharedManagerAdapter { int size(){ int size = 0; - for (Queue queue : buckets) { + for (Queue queue : buckets) size += queue.size(); - } return size; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java index 913e9bc..13b03fe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java @@ -147,7 +147,11 @@ public abstract class GridNearOptimisticTxPrepareFutureAdapter extends GridNearT } if (topFut.isDone()) { - topVer = topFut.topologyVersion(); + if ((topVer = topFut.topologyVersion()) == null && topFut.error() != null) { + onDone(topFut.error()); // Prevent stack overflow if topFut has error. + + return; + } if (remap) tx.onRemap(topVer); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java index b3b43b9..797221e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java @@ -3831,13 +3831,24 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou return chainFinishFuture(finishFut, true, true, false); if (!fastFinish) { - final IgniteInternalFuture prepareFut = prepareNearTxLocal(); + IgniteInternalFuture prepareFut; + try { + prepareFut = prepareNearTxLocal(); + } + catch (Throwable t) { + prepareFut = prepFut; + + // Properly finish prepFut in case of unchecked error. + assert prepareFut != null; // Prep future must be set. + + ((GridNearTxPrepareFutureAdapter)prepFut).onDone(t); + } prepareFut.listen(new CI1>() { @Override public void apply(IgniteInternalFuture f) { try { // Make sure that here are no exceptions. - prepareFut.get(); + f.get(); fut.finish(true, true, false); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRow.java index 92f06a3..746b94a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRow.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRow.java @@ -20,6 +20,9 @@ package org.apache.ignite.internal.processors.cache.persistence; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.mvcc.MvccUpdateVersionAware; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; /** @@ -55,4 +58,9 @@ public interface CacheDataRow extends MvccUpdateVersionAware, CacheSearchRow, St * @param key Key. */ public void key(KeyCacheObject key); + + /** {@inheritDoc} */ + @Override public default IOVersions ioVersions() { + return DataPageIO.VERSIONS; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java index 3e3dc5c..b551f47 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java @@ -233,7 +233,7 @@ public class CacheDataRowAdapter implements CacheDataRow { IoStatisticsHolder statHolder, boolean readCacheId, RowData rowData, - IncompleteObject incomplete, + @Nullable IncompleteObject incomplete, boolean skipVer ) throws IgniteCheckedException { assert link != 0 : "link"; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index 498ccf1..3c40cdf 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -111,6 +111,7 @@ import org.apache.ignite.internal.pagemem.wal.record.MetastoreDataRecord; import org.apache.ignite.internal.pagemem.wal.record.MvccDataEntry; import org.apache.ignite.internal.pagemem.wal.record.MvccTxRecord; import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot; +import org.apache.ignite.internal.pagemem.wal.record.RollbackRecord; import org.apache.ignite.internal.pagemem.wal.record.WALRecord; import org.apache.ignite.internal.pagemem.wal.record.WalRecordCacheGroupAware; import org.apache.ignite.internal.pagemem.wal.record.delta.PageDeltaRecord; @@ -142,7 +143,6 @@ import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemor import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImpl; import org.apache.ignite.internal.processors.cache.persistence.partstate.GroupPartitionId; import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionAllocationMap; -import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionRecoverState; import org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteCacheSnapshotManager; import org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotOperation; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; @@ -2730,9 +2730,12 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan Semaphore semaphore = new Semaphore(semaphorePertmits(exec)); + Map partitionRecoveryStates = new HashMap<>(); + WALIterator it = cctx.wal().replay(status.startPtr, recordTypePredicate); - RestoreLogicalState restoreLogicalState = new RestoreLogicalState(status, it, lastArchivedSegment, cacheGroupsPredicate); + RestoreLogicalState restoreLogicalState = + new RestoreLogicalState(status, it, lastArchivedSegment, cacheGroupsPredicate, partitionRecoveryStates); try { while (it.hasNextX()) { @@ -2742,6 +2745,36 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan break; switch (rec.type()) { + case CHECKPOINT_RECORD: // Calculate initial partition states + CheckpointRecord cpRec = (CheckpointRecord)rec; + + for (Map.Entry entry : cpRec.cacheGroupStates().entrySet()) { + CacheState cacheState = entry.getValue(); + + for (int i = 0; i < cacheState.size(); i++) { + int partId = cacheState.partitionByIndex(i); + byte state = cacheState.stateByIndex(i); + + partitionRecoveryStates.put(new GroupPartitionId(entry.getKey(), partId), (int)state); + } + } + + break; + + case ROLLBACK_TX_RECORD: + RollbackRecord rbRec = (RollbackRecord)rec; + + CacheGroupContext ctx = cctx.cache().cacheGroup(rbRec.groupId()); + + if (ctx != null && !ctx.isLocal()) { + ctx.topology().forceCreatePartition(rbRec.partitionId()); + + ctx.offheap().onPartitionInitialCounterUpdated(rbRec.partitionId(), rbRec.start(), + rbRec.range()); + } + + break; + case MVCC_DATA_RECORD: case DATA_RECORD: case ENCRYPTED_DATA_RECORD: @@ -2773,7 +2806,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan } applied.incrementAndGet(); - }, cacheId, dataEntry.partitionId(), exec, semaphore); + }, cacheDesc.groupId(), dataEntry.partitionId(), exec, semaphore); } break; @@ -2794,11 +2827,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan metaStateRecord.groupId(), metaStateRecord.partitionId() ); - PartitionRecoverState state = new PartitionRecoverState( - (int)metaStateRecord.state(), metaStateRecord.updateCounter() - ); - - restoreLogicalState.partitionRecoveryStates.put(groupPartitionId, state); + restoreLogicalState.partitionRecoveryStates.put(groupPartitionId, (int)metaStateRecord.state()); break; @@ -2925,7 +2954,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan } if (dataEntry.partitionCounter() != 0) - cacheCtx.offheap().onPartitionInitialCounterUpdated(partId, dataEntry.partitionCounter()); + cacheCtx.offheap().onPartitionInitialCounterUpdated(partId, dataEntry.partitionCounter() - 1, 1); break; @@ -2944,7 +2973,7 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan cacheCtx.offheap().remove(cacheCtx, dataEntry.key(), partId, locPart); if (dataEntry.partitionCounter() != 0) - cacheCtx.offheap().onPartitionInitialCounterUpdated(partId, dataEntry.partitionCounter()); + cacheCtx.offheap().onPartitionInitialCounterUpdated(partId, dataEntry.partitionCounter() - 1, 1); break; @@ -5347,13 +5376,13 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan assert pageStore != null : "Persistent cache should have initialize page store manager."; for (int p = 0; p < grp.affinity().partitions(); p++) { - if (grp.topology().localPartition(p) != null) { - GridDhtLocalPartition part = grp.topology().localPartition(p); + GridDhtLocalPartition part = grp.topology().localPartition(p); + if (part != null) { log.info("Partition [grp=" + grp.cacheOrGroupName() + ", id=" + p + ", state=" + part.state() - + ", counter=" + part.updateCounter() + + ", counter=" + part.dataStore().partUpdateCounter() + ", size=" + part.fullSize() + "]"); continue; @@ -5379,17 +5408,17 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan try { PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.forPage(pageAddr); - GridDhtPartitionState partitionState = fromOrdinal(io.getPartitionState(pageAddr)); + GridDhtPartitionState partState = fromOrdinal(io.getPartitionState(pageAddr)); - String state = partitionState != null ? partitionState.toString() : "N/A"; + String state = partState != null ? partState.toString() : "N/A"; - long updateCounter = io.getUpdateCounter(pageAddr); + long updateCntr = io.getUpdateCounter(pageAddr); long size = io.getSize(pageAddr); log.info("Partition [grp=" + grp.cacheOrGroupName() + ", id=" + p + ", state=" + state - + ", counter=" + updateCounter + + ", counter=" + updateCntr + ", size=" + size + "]"); } finally { @@ -5453,11 +5482,12 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan } /** - * @return WAL records predicate that passes only logical and mixed WAL records. + * @return WAL records predicate that passes only logical and mixed WAL records + + * CP record (used for restoring initial partition states). */ private IgniteBiPredicate logicalRecords() { return (type, ptr) -> type.purpose() == WALRecord.RecordPurpose.LOGICAL - || type.purpose() == WALRecord.RecordPurpose.MIXED; + || type.purpose() == WALRecord.RecordPurpose.MIXED || type == CHECKPOINT_RECORD; } /** @@ -5670,19 +5700,23 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan */ public class RestoreLogicalState extends RestoreStateContext { /** States of partitions recovered during applying logical updates. */ - private final Map partitionRecoveryStates = new HashMap<>(); + private final Map partitionRecoveryStates; /** * @param lastArchivedSegment Last archived segment index. + * @param partitionRecoveryStates Initial partition recovery states. */ - public RestoreLogicalState(CheckpointStatus status, WALIterator iterator, long lastArchivedSegment, IgnitePredicate cacheGroupsPredicate) { + public RestoreLogicalState(CheckpointStatus status, WALIterator iterator, long lastArchivedSegment, + IgnitePredicate cacheGroupsPredicate, Map partitionRecoveryStates) { super(status, iterator, lastArchivedSegment, cacheGroupsPredicate); + + this.partitionRecoveryStates = partitionRecoveryStates; } /** * @return Map of restored partition states for cache groups. */ - public Map partitionRecoveryStates() { + public Map partitionRecoveryStates() { return Collections.unmodifiableMap(partitionRecoveryStates); } } 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 84a23d3..942a713 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 @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.persistence; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -31,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteLogger; import org.apache.ignite.failure.FailureContext; import org.apache.ignite.failure.FailureType; import org.apache.ignite.internal.pagemem.FullPageId; @@ -45,9 +47,10 @@ import org.apache.ignite.internal.pagemem.wal.WALPointer; import org.apache.ignite.internal.pagemem.wal.record.DataEntry; import org.apache.ignite.internal.pagemem.wal.record.DataRecord; import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot; +import org.apache.ignite.internal.pagemem.wal.record.RollbackRecord; import org.apache.ignite.internal.pagemem.wal.record.WALRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRecord; -import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdatePartitionDataRecord; +import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdatePartitionDataRecordV2; import org.apache.ignite.internal.pagemem.wal.record.delta.PartitionDestroyRecord; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryPredicate; @@ -59,6 +62,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheTtlManager; import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManagerImpl; import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.internal.processors.cache.PartitionUpdateCounter; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.CachePartitionPartialCountersMap; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.IgniteHistoricalIterator; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; @@ -66,12 +70,15 @@ import org.apache.ignite.internal.processors.cache.distributed.dht.topology.Grid import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot; import org.apache.ignite.internal.processors.cache.mvcc.MvccVersion; import org.apache.ignite.internal.processors.cache.persistence.freelist.CacheFreeListImpl; +import org.apache.ignite.internal.processors.cache.persistence.freelist.AbstractFreeList; +import org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow; import org.apache.ignite.internal.processors.cache.persistence.migration.UpgradePendingTreeToPerPartitionTask; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryEx; import org.apache.ignite.internal.processors.cache.persistence.partstate.GroupPartitionId; import org.apache.ignite.internal.processors.cache.persistence.partstate.PagesAllocationRange; import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionAllocationMap; -import org.apache.ignite.internal.processors.cache.persistence.partstate.PartitionRecoverState; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorage; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorageImpl; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageMetaIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionCountersIO; @@ -267,14 +274,18 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple if (rowStore0 != null) { ((CacheFreeListImpl)rowStore0.freeList()).saveMetadata(); + PartitionMetaStorage partStore = store.partStorage(); + long updCntr = store.updateCounter(); long size = store.fullSize(); long rmvId = globalRemoveId().get(); + byte[] updCntrsBytes = store.partUpdateCounter().getBytes(); + PageMemoryEx pageMem = (PageMemoryEx)grp.dataRegion().pageMemory(); IgniteWriteAheadLogManager wal = this.ctx.wal(); - if (size > 0 || updCntr > 0) { + if (size > 0 || updCntr > 0 || !store.partUpdateCounter().sequential()) { GridDhtPartitionState state = null; // localPartition will not acquire writeLock here because create=false. @@ -313,7 +324,46 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple boolean changed = false; try { - PagePartitionMetaIO io = PageIO.getPageIO(partMetaPageAddr); + PagePartitionMetaIOV2 io = PageIO.getPageIO(partMetaPageAddr); + + long link = io.getGapsLink(partMetaPageAddr); + + if (updCntrsBytes == null && link != 0) { + partStore.removeDataRowByLink(link, grp.statisticsHolderData()); + + io.setGapsLink(partMetaPageAddr, (link = 0)); + + changed = true; + } + else if (updCntrsBytes != null && link == 0) { + SimpleDataRow row = new SimpleDataRow(store.partId(), updCntrsBytes); + + partStore.insertDataRow(row, grp.statisticsHolderData()); + + io.setGapsLink(partMetaPageAddr, (link = row.link())); + + changed = true; + } + else if (updCntrsBytes != null && link != 0) { + byte[] prev = partStore.readRow(link); + + assert prev != null : "Read null gaps using link=" + link; + + if (!Arrays.equals(prev, updCntrsBytes)) { + partStore.removeDataRowByLink(link, grp.statisticsHolderData()); + + SimpleDataRow row = new SimpleDataRow(store.partId(), updCntrsBytes); + + partStore.insertDataRow(row, grp.statisticsHolderData()); + + io.setGapsLink(partMetaPageAddr, (link = row.link())); + + changed = true; + } + } + + if (changed) + partStore.saveMetadata(); changed |= io.setUpdateCounter(partMetaPageAddr, updCntr); changed |= io.setGlobalRemoveId(partMetaPageAddr, rmvId); @@ -386,7 +436,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple pageCnt = io.getCandidatePageCount(partMetaPageAddr); if (changed && PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null)) - wal.log(new MetaPageUpdatePartitionDataRecord( + wal.log(new MetaPageUpdatePartitionDataRecordV2( grpId, partMetaId, updCntr, @@ -394,7 +444,8 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple (int)size, // TODO: Partition size may be long cntrsPageId, state == null ? -1 : (byte)state.ordinal(), - pageCnt + pageCnt, + link )); } finally { @@ -413,7 +464,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException { + @Override public long restorePartitionStates(Map partitionRecoveryStates) throws IgniteCheckedException { if (grp.isLocal() || !grp.affinityNode() || !grp.dataRegion().config().isPersistenceEnabled()) return 0; @@ -425,7 +476,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple PageMemoryEx pageMem = (PageMemoryEx)grp.dataRegion().pageMemory(); for (int p = 0; p < grp.affinity().partitions(); p++) { - PartitionRecoverState recoverState = partitionRecoveryStates.get(new GroupPartitionId(grp.groupId(), p)); + Integer recoverState = partitionRecoveryStates.get(new GroupPartitionId(grp.groupId(), p)); if (ctx.pageStore().exists(grp.groupId(), p)) { ctx.pageStore().ensure(grp.groupId(), p); @@ -446,7 +497,8 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple GridDhtLocalPartition part = grp.topology().forceCreatePartition(p); - onPartitionInitialCounterUpdated(p, 0); + // Triggers initialization of existing(having datafile) partition before acquiring cp read lock. + part.dataStore().init(); ctx.database().checkpointReadLock(); @@ -463,17 +515,9 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.forPage(pageAddr); if (recoverState != null) { - io.setPartitionState(pageAddr, (byte) recoverState.stateId()); + io.setPartitionState(pageAddr, (byte) recoverState.intValue()); - changed = updateState(part, recoverState.stateId()); - - if (recoverState.stateId() == GridDhtPartitionState.OWNING.ordinal() - || (recoverState.stateId() == GridDhtPartitionState.MOVING.ordinal() - && part.initialUpdateCounter() < recoverState.updateCounter())) { - part.initialUpdateCounter(recoverState.updateCounter()); - - changed = true; - } + changed = updateState(part, recoverState); if (log.isDebugEnabled()) log.debug("Restored partition state (from WAL) " + @@ -503,12 +547,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple ctx.database().checkpointReadUnlock(); } } - else if (recoverState != null) { + else if (recoverState != null && recoverState >= 0) { // Pre-create partition if having valid state. GridDhtLocalPartition part = grp.topology().forceCreatePartition(p); - onPartitionInitialCounterUpdated(p, recoverState.updateCounter()); - - updateState(part, recoverState.stateId()); + updateState(part, recoverState); processed++; @@ -816,15 +858,12 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public void onPartitionInitialCounterUpdated(int part, long cntr) { + @Override public void onPartitionInitialCounterUpdated(int part, long start, long delta) { CacheDataStore store = partDataStores.get(part); assert store != null; - long oldCnt = store.initialUpdateCounter(); - - if (oldCnt < cntr) - store.updateInitialCounter(cntr); + store.updateInitialCounter(start, delta); } /** {@inheritDoc} */ @@ -911,6 +950,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple return new Metas( new RootPage(new FullPageId(metastoreRoot, grpId), allocated), new RootPage(new FullPageId(reuseListRoot, grpId), allocated), + null, null); } finally { @@ -951,7 +991,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple WALIterator it = grp.shared().wal().replay(minPtr); - WALHistoricalIterator iterator = new WALHistoricalIterator(grp, partCntrs, it); + WALHistoricalIterator iterator = new WALHistoricalIterator(log, grp, partCntrs, it); // Add historical partitions which are unabled to reserve to missing set. missing.addAll(iterator.missingParts); @@ -1024,7 +1064,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple for (CacheDataStore store : partDataStores.values()) { assert store instanceof GridCacheDataStore; - CacheFreeListImpl freeList = ((GridCacheDataStore)store).freeList; + AbstractFreeList freeList = ((GridCacheDataStore)store).freeList; if (freeList == null) continue; @@ -1046,7 +1086,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple for (CacheDataStore store : partDataStores.values()) { assert store instanceof GridCacheDataStore; - CacheFreeListImpl freeList = ((GridCacheDataStore)store).freeList; + AbstractFreeList freeList = ((GridCacheDataStore)store).freeList; if (freeList == null) continue; @@ -1094,6 +1134,9 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple /** */ private static final long serialVersionUID = 0L; + /** Logger. */ + private IgniteLogger log; + /** Cache context. */ private final CacheGroupContext grp; @@ -1118,24 +1161,34 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple /** */ private DataEntry next; - /** Flag indicates that partition belongs to current {@link #next} is finished and no longer needs to rebalance. */ - private boolean reachedPartitionEnd; + /** + * Rebalanced counters in the range from initialUpdateCntr to updateCntr. + * Invariant: initUpdCntr[idx] + rebalancedCntrs[idx] = updateCntr[idx] + */ + private long[] rebalancedCntrs; - /** Flag indicates that update counters for requested partitions have been reached and done. - * It means that no further iteration is needed. */ - private boolean doneAllPartitions; + /** A partition what will be finished on next iteration. */ + private int donePart = -1; /** + * @param log Logger. * @param grp Cache context. * @param walIt WAL iterator. */ - private WALHistoricalIterator(CacheGroupContext grp, CachePartitionPartialCountersMap partMap, WALIterator walIt) { + private WALHistoricalIterator(IgniteLogger log, CacheGroupContext grp, CachePartitionPartialCountersMap partMap, + WALIterator walIt) { + this.log = log; this.grp = grp; this.partMap = partMap; this.walIt = walIt; cacheIds = grp.cacheIds(); + rebalancedCntrs = new long[partMap.size()]; + + for (int i = 0; i < rebalancedCntrs.length; i++) + rebalancedCntrs[i] = partMap.initialUpdateCounterAt(i); + reservePartitions(); advance(); @@ -1194,13 +1247,19 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple CacheDataRow val = new DataEntryRow(next); - if (reachedPartitionEnd) { - doneParts.add(next.partitionId()); + if (donePart != -1) { + int pIdx = partMap.partitionIndex(donePart); + + if (log.isDebugEnabled()) { + log.debug("Partition done [grpId=" + grp.groupId() + + ", partId=" + donePart + + ", from=" + partMap.initialUpdateCounterAt(pIdx) + + ", to=" + partMap.updateCounterAt(pIdx) + ']'); + } - reachedPartitionEnd = false; + doneParts.add(donePart); - if (doneParts.size() == partMap.size()) - doneAllPartitions = true; + donePart = -1; } advance(); @@ -1259,10 +1318,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple private void advance() { next = null; - if (doneAllPartitions) - return; - - while (true) { + outer: while (doneParts.size() != partMap.size()) { if (entryIt != null) { while (entryIt.hasNext()) { DataEntry entry = entryIt.next(); @@ -1277,8 +1333,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple long to = partMap.updateCounterAt(idx); if (entry.partitionCounter() > from && entry.partitionCounter() <= to) { - if (entry.partitionCounter() == to) - reachedPartitionEnd = true; + // Partition will be marked as done for current entry on next iteration. + if (++rebalancedCntrs[idx] == to || + entry.partitionCounter() == to && grp.hasAtomicCaches()) + donePart = entry.partitionId(); next = entry; @@ -1290,6 +1348,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple entryIt = null; + // Search for next DataEntry while applying rollback counters. while (walIt.hasNext()) { IgniteBiTuple rec = walIt.next(); @@ -1297,14 +1356,38 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple DataRecord data = (DataRecord)rec.get2(); entryIt = data.writeEntries().iterator(); + // Move on to the next valid data entry. + continue outer; + } + else if (rec.get2() instanceof RollbackRecord) { + RollbackRecord rbRec = (RollbackRecord)rec.get2(); - break; + if (grp.groupId() == rbRec.groupId()) { + int idx = partMap.partitionIndex(rbRec.partitionId()); + + if (idx < 0 || missingParts.contains(idx)) + continue; + + long from = partMap.initialUpdateCounterAt(idx); + long to = partMap.updateCounterAt(idx); + + rebalancedCntrs[idx] += rbRec.overlap(from, to); + + if (rebalancedCntrs[idx] == partMap.updateCounterAt(idx)) { + if (log.isDebugEnabled()) { + log.debug("Partition done [partId=" + donePart + + " from=" + from + " to=" + to + ']'); + } + + doneParts.add(rbRec.partitionId()); // Add to done set immediately. + } + } } } - if (entryIt == null) - return; + assert entryIt != null || doneParts.size() == partMap.size() : + "Reached end of WAL but not all partitions are done"; } } } @@ -1440,14 +1523,19 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple @GridToStringInclude private final RootPage pendingTreeRoot; + /** */ + @GridToStringInclude + private final RootPage partMetastoreReuseListRoot; + /** * @param treeRoot Metadata storage root. * @param reuseListRoot Reuse list root. */ - Metas(RootPage treeRoot, RootPage reuseListRoot, RootPage pendingTreeRoot) { + Metas(RootPage treeRoot, RootPage reuseListRoot, RootPage pendingTreeRoot, RootPage partMetastoreReuseListRoot) { this.treeRoot = treeRoot; this.reuseListRoot = reuseListRoot; this.pendingTreeRoot = pendingTreeRoot; + this.partMetastoreReuseListRoot = partMetastoreReuseListRoot; } /** {@inheritDoc} */ @@ -1467,13 +1555,13 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple private String name; /** */ - private volatile CacheFreeListImpl freeList; + private volatile AbstractFreeList freeList; /** */ private PendingEntriesTree pendingTree; /** */ - private volatile CacheDataStore delegate; + private volatile CacheDataStoreImpl delegate; /** * Cache id which should be throttled. @@ -1488,6 +1576,9 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple private volatile long nextStoreCleanTime; /** */ + private PartitionMetaStorage partStorage; + + /** */ private final boolean exists; /** */ @@ -1512,7 +1603,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple * @throws IgniteCheckedException If failed. */ private CacheDataStore init0(boolean checkExists) throws IgniteCheckedException { - CacheDataStore delegate0 = delegate; + CacheDataStoreImpl delegate0 = delegate; if (delegate0 != null) return delegate0; @@ -1532,7 +1623,9 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple if (PageIdUtils.partId(metas.reuseListRoot.pageId().pageId()) != partId || PageIdUtils.partId(metas.treeRoot.pageId().pageId()) != partId || - PageIdUtils.partId(metas.pendingTreeRoot.pageId().pageId()) != partId) { + PageIdUtils.partId(metas.pendingTreeRoot.pageId().pageId()) != partId || + PageIdUtils.partId(metas.partMetastoreReuseListRoot.pageId().pageId()) != partId + ) { throw new IgniteCheckedException("Invalid meta root allocated [" + "cacheOrGroupName=" + grp.cacheOrGroupName() + ", partId=" + partId + @@ -1558,6 +1651,25 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } }; + RootPage partMetastoreReuseListRoot = metas.partMetastoreReuseListRoot; + + partStorage = new PartitionMetaStorageImpl( + grp.groupId(), + grp.cacheOrGroupName() + "-partstore-" + partId, + grp.dataRegion().memoryMetrics(), + grp.dataRegion(), + freeList, + ctx.wal(), + partMetastoreReuseListRoot.pageId().pageId(), + partMetastoreReuseListRoot.isAllocated()) { + /** {@inheritDoc} */ + @Override protected long allocatePageNoReuse() throws IgniteCheckedException { + assert grp.shared().database().checkpointLockIsHeldByThread(); + + return pageMem.allocatePage(grpId, partId, PageIdAllocator.FLAG_DATA); + } + }; + CacheDataRowStore rowStore = new CacheDataRowStore(grp, freeList, partId); RootPage treeRoot = metas.treeRoot; @@ -1642,14 +1754,18 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple try { if (PageIO.getType(pageAddr) != 0) { - PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest(); + PagePartitionMetaIOV2 io = (PagePartitionMetaIOV2)PagePartitionMetaIO.VERSIONS.latest(); Map cacheSizes = null; if (grp.sharedGroup()) cacheSizes = readSharedGroupCacheSizes(pageMem, grpId, io.getCountersPageId(pageAddr)); - delegate0.init(io.getSize(pageAddr), io.getUpdateCounter(pageAddr), cacheSizes); + long link = io.getGapsLink(pageAddr); + + byte[] data = link == 0 ? null : partStorage.readRow(link); + + delegate0.restoreState(io.getSize(pageAddr), io.getUpdateCounter(pageAddr), cacheSizes, data); globalRemoveId().setIfGreater(io.getGlobalRemoveId(pageAddr)); } @@ -1704,28 +1820,32 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple try { boolean allocated = false; boolean pendingTreeAllocated = false; + boolean partMetastoreReuseListAllocated = false; long pageAddr = pageMem.writeLock(grpId, partMetaId, partMetaPage); try { - long treeRoot, reuseListRoot, pendingTreeRoot; + long treeRoot, reuseListRoot, pendingTreeRoot, partMetaStoreReuseListRoot; // Initialize new page. if (PageIO.getType(pageAddr) != PageIO.T_PART_META) { - PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest(); + PagePartitionMetaIOV2 io = (PagePartitionMetaIOV2)PagePartitionMetaIO.VERSIONS.latest(); io.initNewPage(pageAddr, partMetaId, pageMem.realPageSize(grpId)); treeRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); reuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); pendingTreeRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); + partMetaStoreReuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); assert PageIdUtils.flag(treeRoot) == PageMemory.FLAG_DATA; assert PageIdUtils.flag(reuseListRoot) == PageMemory.FLAG_DATA; assert PageIdUtils.flag(pendingTreeRoot) == PageMemory.FLAG_DATA; + assert PageIdUtils.flag(partMetaStoreReuseListRoot) == PageMemory.FLAG_DATA; io.setTreeRoot(pageAddr, treeRoot); io.setReuseListRoot(pageAddr, reuseListRoot); io.setPendingTreeRoot(pageAddr, pendingTreeRoot); + io.setPartitionMetaStoreReuseListRoot(pageAddr, partMetaStoreReuseListRoot); if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null)) { wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr, @@ -1740,14 +1860,14 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple treeRoot = io.getTreeRoot(pageAddr); reuseListRoot = io.getReuseListRoot(pageAddr); - int pageVersion = PagePartitionMetaIO.getVersion(pageAddr); + int pageVer = PagePartitionMetaIO.getVersion(pageAddr); - if (pageVersion < 2) { - assert pageVersion == 1; + if (pageVer < 2) { + assert pageVer == 1; if (log.isDebugEnabled()) log.info("Upgrade partition meta page version: [part=" + partId + - ", grpId=" + grpId + ", oldVer=" + pageVersion + + ", grpId=" + grpId + ", oldVer=" + pageVer + ", newVer=" + io.getVersion() ); @@ -1756,8 +1876,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple ((PagePartitionMetaIOV2)io).upgradePage(pageAddr); pendingTreeRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); + partMetaStoreReuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); io.setPendingTreeRoot(pageAddr, pendingTreeRoot); + io.setPartitionMetaStoreReuseListRoot(pageAddr, partMetaStoreReuseListRoot); if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null)) { @@ -1765,10 +1887,24 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple pageMem.pageSize(), pageMem.realPageSize(grpId))); } - pendingTreeAllocated = true; + pendingTreeAllocated = partMetastoreReuseListAllocated = true; } - else + else { pendingTreeRoot = io.getPendingTreeRoot(pageAddr); + partMetaStoreReuseListRoot = io.getPartitionMetaStoreReuseListRoot(pageAddr); + + if (partMetaStoreReuseListRoot == 0) { + partMetaStoreReuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA); + + if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, + null)) { + wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr, + pageMem.pageSize(), pageMem.realPageSize(grpId))); + } + + partMetastoreReuseListAllocated = true; + } + } if (PageIdUtils.flag(treeRoot) != PageMemory.FLAG_DATA) throw new StorageException("Wrong tree root page id flag: treeRoot=" @@ -1781,15 +1917,21 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple if (PageIdUtils.flag(pendingTreeRoot) != PageMemory.FLAG_DATA) throw new StorageException("Wrong pending tree root page id flag: reuseListRoot=" + U.hexLong(reuseListRoot) + ", part=" + partId + ", grpId=" + grpId); + + if (PageIdUtils.flag(partMetaStoreReuseListRoot) != PageMemory.FLAG_DATA) + throw new StorageException("Wrong partition meta store list root page id flag: partMetaStoreReuseListRoot=" + + U.hexLong(partMetaStoreReuseListRoot) + ", part=" + partId + ", grpId=" + grpId); } return new Metas( new RootPage(new FullPageId(treeRoot, grpId), allocated), new RootPage(new FullPageId(reuseListRoot, grpId), allocated), - new RootPage(new FullPageId(pendingTreeRoot, grpId), allocated || pendingTreeAllocated)); + new RootPage(new FullPageId(pendingTreeRoot, grpId), allocated || pendingTreeAllocated), + new RootPage(new FullPageId(partMetaStoreReuseListRoot, grpId), allocated || partMetastoreReuseListAllocated)); } finally { - pageMem.writeUnlock(grpId, partMetaId, partMetaPage, null, allocated || pendingTreeAllocated); + pageMem.writeUnlock(grpId, partMetaId, partMetaPage, null, + allocated || pendingTreeAllocated || partMetastoreReuseListAllocated); } } finally { @@ -1798,6 +1940,16 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ + @Override public boolean init() { + try { + return init0(true) != null; + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + + /** {@inheritDoc} */ @Override public int partId() { return partId; } @@ -1888,10 +2040,34 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public long getAndIncrementUpdateCounter(long delta) { + @Override public long reservedCounter() { + try { + CacheDataStore delegate0 = init0(true); + + return delegate0 == null ? 0 : delegate0.reservedCounter(); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + + /** {@inheritDoc} */ + @Override public PartitionUpdateCounter partUpdateCounter() { try { CacheDataStore delegate0 = init0(true); + return delegate0 == null ? null : delegate0.partUpdateCounter(); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + + /** {@inheritDoc} */ + @Override public long getAndIncrementUpdateCounter(long delta) { + try { + CacheDataStore delegate0 = init0(false); + return delegate0 == null ? 0 : delegate0.getAndIncrementUpdateCounter(delta); } catch (IgniteCheckedException e) { @@ -1900,8 +2076,18 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public void init(long size, long updCntr, @Nullable Map cacheSizes) { - throw new IllegalStateException("Should be never called."); + @Override public long reserve(long delta) { + try { + CacheDataStore delegate0 = init0(false); + + if (delegate0 == null) + throw new IllegalStateException("Should be never called."); + + return delegate0.reserve(delta); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } } /** {@inheritDoc} */ @@ -1918,12 +2104,11 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public void updateCounter(long start, long delta) { + @Override public boolean updateCounter(long start, long delta) { try { CacheDataStore delegate0 = init0(false); - if (delegate0 != null) - delegate0.updateCounter(start, delta); + return delegate0 != null && delegate0.updateCounter(start, delta); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -1947,7 +2132,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple try { CacheDataStore delegate0 = init0(false); - return delegate0 == null ? 0 : delegate0.nextUpdateCounter(); + if (delegate0 == null) + throw new IllegalStateException("Should be never called."); + + return delegate0.nextUpdateCounter(); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -1967,12 +2155,14 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** {@inheritDoc} */ - @Override public void updateInitialCounter(long cntr) { + @Override public void updateInitialCounter(long start, long delta) { try { CacheDataStore delegate0 = init0(true); - if (delegate0 != null) - delegate0.updateInitialCounter(cntr); + if (delegate0 == null) + throw new IllegalStateException("Should be never called."); + + delegate0.updateInitialCounter(start, delta); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -2495,6 +2685,25 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple if (delegate0 != null) delegate0.preload(); } + + /** {@inheritDoc} */ + @Override public void resetUpdateCounter() { + try { + CacheDataStore delegate0 = init0(true); + + if (delegate0 == null) + return; + + delegate0.resetUpdateCounter(); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + + @Override public PartitionMetaStorage partStorage() { + return partStorage; + } } /** 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 91fd207..9a3d9d2 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 @@ -18,6 +18,7 @@ package org.apache.ignite.internal.processors.cache.persistence; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.processors.cache.CacheGroupContext; import org.apache.ignite.internal.processors.cache.CacheObjectContext; @@ -26,6 +27,7 @@ import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler; import org.apache.ignite.internal.processors.query.GridQueryRowCacheCleaner; import org.apache.ignite.internal.stat.IoStatisticsHolder; +import org.apache.ignite.internal.util.typedef.internal.U; /** * Data store for H2 rows. @@ -109,6 +111,10 @@ public class RowStore { ctx.database().checkpointReadUnlock(); } } + + assert row.key().partition() == PageIdUtils.partId(row.link()) : + "Constructed a link with invalid partition ID [partId=" + row.key().partition() + + ", link=" + U.hexLong(row.link()) + ']'; } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java index 133f0a1..d8fe3a4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.processors.cache.persistence; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; /** * Simple interface for data, store in some RowStore. @@ -49,4 +51,9 @@ public interface Storable { * which is entirely available on the very first page followed by the row link. */ public int headerSize(); + + /** + * @return I/O for handling this storable. + */ + public IOVersions ioVersions(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/checkpoint/CheckpointEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/checkpoint/CheckpointEntry.java index c26e0a3..e7bcb05 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/checkpoint/CheckpointEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/checkpoint/CheckpointEntry.java @@ -20,7 +20,6 @@ package org.apache.ignite.internal.processors.cache.persistence.checkpoint; import java.lang.ref.SoftReference; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -275,7 +274,7 @@ public class CheckpointEntry { if (stateRec == null) return Collections.emptyMap(); - Map grpStates = new HashMap<>(stateRec.size()); + Map grpStates = U.newHashMap(stateRec.size()); for (Integer grpId : stateRec.keySet()) { CacheState recState = stateRec.get(grpId); 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 958fb31..5742b74 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 @@ -34,7 +34,6 @@ import org.apache.ignite.internal.processors.cache.persistence.Storable; import org.apache.ignite.internal.processors.cache.persistence.evict.PageEvictionTracker; import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPagePayload; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.LongListReuseBag; import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseBag; @@ -484,23 +483,32 @@ public abstract class AbstractFreeList extends PagesList imp long pageId = 0L; - for (int b = remaining < MIN_SIZE_FOR_DATA_PAGE ? bucket(remaining, false) + 1 : REUSE_BUCKET; b < BUCKETS; b++) { - pageId = takeEmptyPage(b, ioVersions(), 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); - if (pageId != 0L) - break; + 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; + AbstractDataPageIO initIo = null; if (pageId == 0L) { pageId = allocateDataPage(row.partition()); - initIo = ioVersions().latest(); + initIo = row.ioVersions().latest(); } - else if (PageIdUtils.tag(pageId) != PageIdAllocator.FLAG_DATA) - pageId = initReusedPage(pageId, row.partition(), statHolder); - else + 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); @@ -525,7 +533,7 @@ public abstract class AbstractFreeList extends PagesList imp * * @see PagesList#initReusedPage(long, long, long, int, byte, PageIO) */ - private long initReusedPage(long reusedPageId, int partId, + private long initReusedPage(T row, long reusedPageId, int partId, IoStatisticsHolder statHolder) throws IgniteCheckedException { long reusedPage = acquirePage(reusedPageId, statHolder); try { @@ -535,7 +543,7 @@ public abstract class AbstractFreeList extends PagesList imp try { return initReusedPage(reusedPageId, reusedPage, reusedPageAddr, - partId, PageIdAllocator.FLAG_DATA, ioVersions().latest()); + partId, PageIdAllocator.FLAG_DATA, row.ioVersions().latest()); } finally { writeUnlock(reusedPageId, reusedPage, reusedPageAddr, true); @@ -694,11 +702,6 @@ public abstract class AbstractFreeList extends PagesList imp } } - /** - * @return IOVersions. - */ - public abstract IOVersions> ioVersions(); - /** {@inheritDoc} */ @Override public String toString() { return "FreeList [name=" + name + ']'; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeListImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeListImpl.java index 625c0b1..c1a58de 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeListImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeListImpl.java @@ -23,9 +23,6 @@ import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager; 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.DataRegionMetricsImpl; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; import org.apache.ignite.internal.stat.IoStatisticsHolder; import org.apache.ignite.internal.util.typedef.internal.U; @@ -51,17 +48,12 @@ public class CacheFreeListImpl extends AbstractFreeList { } /** {@inheritDoc} */ - @Override public IOVersions> ioVersions() { - return DataPageIO.VERSIONS; - } - - /** {@inheritDoc} */ @Override public void insertDataRow(CacheDataRow row, IoStatisticsHolder statHolder) throws IgniteCheckedException { super.insertDataRow(row, statHolder); assert row.key().partition() == PageIdUtils.partId(row.link()) : "Constructed a link with invalid partition ID [partId=" + row.key().partition() + - ", link=" + U.hexLong(row.link()) + ']'; + ", link=" + U.hexLong(row.link()) + ']'; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java index e5cb3a6..1855578 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java @@ -660,7 +660,7 @@ public abstract class PagesList extends DataStructure { * @throws IgniteCheckedException If failed. */ protected final void put( - ReuseBag bag, + @Nullable ReuseBag bag, final long dataId, final long dataPage, final long dataAddr, @@ -669,10 +669,13 @@ public abstract class PagesList extends DataStructure { throws IgniteCheckedException { assert bag == null ^ dataAddr == 0L; + if (bag != null && bag.isEmpty()) // Skip allocating stripe for empty bag. + return; + for (int lockAttempt = 0; ;) { Stripe stripe = getPageForPut(bucket, bag); - // No need to continue if bag has been utilized at getPageForPut. + // No need to continue if bag has been utilized at getPageForPut (free page can be used for pagelist). if (bag != null && bag.isEmpty()) return; @@ -936,7 +939,6 @@ public abstract class PagesList extends DataStructure { int idx = io.addPage(prevAddr, nextId, pageSize()); if (idx == -1) { // Attempt to add page failed: the node page is full. - final long nextPage = acquirePage(nextId, statHolder); try { @@ -1095,7 +1097,7 @@ public abstract class PagesList extends DataStructure { * @return Removed page ID. * @throws IgniteCheckedException If failed. */ - protected final long takeEmptyPage(int bucket, @Nullable IOVersions initIoVers, + protected long takeEmptyPage(int bucket, @Nullable IOVersions initIoVers, IoStatisticsHolder statHolder) throws IgniteCheckedException { for (int lockAttempt = 0; ;) { Stripe stripe = getPageForTake(bucket); @@ -1278,6 +1280,8 @@ public abstract class PagesList extends DataStructure { } /** + * Removes data page from bucket, merges bucket list if needed. + * * @param dataId Data page ID. * @param dataPage Data page pointer. * @param dataAddr Data page address. @@ -1642,7 +1646,7 @@ public abstract class PagesList extends DataStructure { public volatile long tailId; /** */ - volatile boolean empty; + public volatile boolean empty; /** * @param tailId Tail ID. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/SimpleDataRow.java similarity index 51% copy from modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java copy to modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/SimpleDataRow.java index 2d7b0a6..6061ff7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/SimpleDataRow.java @@ -15,60 +15,68 @@ * limitations under the License. */ -package org.apache.ignite.internal.processors.cache.persistence.metastorage; +package org.apache.ignite.internal.processors.cache.persistence.freelist; import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.pagemem.PageIdAllocator; import org.apache.ignite.internal.processors.cache.persistence.Storable; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.SimpleDataPageIO; +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.internal.S; /** - * + * Implementation of {@link Storable} which holds byte array of variable length. */ -public class MetastorageDataRow implements MetastorageSearchRow, Storable { +public class SimpleDataRow implements Storable { /** */ private long link; /** */ - private String key; + private final int part; /** */ - private byte[] value; + @GridToStringExclude + private final byte[] val; - /** */ - public MetastorageDataRow(long link, String key, byte[] value) { + /** + * @param link Link. + * @param part Partition. + * @param val Value. + */ + public SimpleDataRow(long link, int part, byte[] val) { this.link = link; - this.key = key; - this.value = value; - } - - /** */ - public MetastorageDataRow(String key, byte[] value) { - this.key = key; - this.value = value; + this.part = part; + this.val = val; } /** - * @return Key. + * @param part Partition. + * @param val Value. */ - @Override public String key() { - return key; + public SimpleDataRow(int part, byte[] val) { + this.part = part; + this.val = val; + } + + /** {@inheritDoc} */ + @Override public void link(long link) { + this.link = link; } /** {@inheritDoc} */ - @Override - public int hash() { - return key.hashCode(); + @Override public long link() { + return link; } /** {@inheritDoc} */ - @Override - public int partition() { - return MetaStorage.PRESERVE_LEGACY_METASTORAGE_PARTITION_ID ? PageIdAllocator.OLD_METASTORE_PARTITION: PageIdAllocator.METASTORE_PARTITION; + @Override public int partition() { + return part; } /** {@inheritDoc} */ @Override public int size() throws IgniteCheckedException { - return 4 + value().length; + return 2 /** Fragment size */ + 2 /** Row size */ + value().length; } /** {@inheritDoc} */ @@ -77,27 +85,17 @@ public class MetastorageDataRow implements MetastorageSearchRow, Storable { } /** {@inheritDoc} */ - @Override - public void link(long link) { - this.link = link; + public byte[] value() { + return val; } /** {@inheritDoc} */ - @Override - public long link() { - return link; - } - - /** - * @return Value. - */ - public byte[] value() { - return value; + @Override public IOVersions ioVersions() { + return SimpleDataPageIO.VERSIONS; } /** {@inheritDoc} */ - @Override - public String toString() { - return "key=" + key; + @Override public String toString() { + return S.toString(SimpleDataRow.class, this, "len", val.length); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java index cfab287..331da92 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java @@ -50,7 +50,6 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRecord; import org.apache.ignite.internal.processors.cache.CacheGroupContext; import org.apache.ignite.internal.processors.cache.GridCacheProcessor; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.cache.IncompleteObject; 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.DbCheckpointListener; @@ -58,15 +57,10 @@ import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabase import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager; import org.apache.ignite.internal.processors.cache.persistence.RootPage; import org.apache.ignite.internal.processors.cache.persistence.StorageException; -import org.apache.ignite.internal.processors.cache.persistence.freelist.AbstractFreeList; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryEx; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPagePayload; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorageImpl; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionMetaIO; -import org.apache.ignite.internal.processors.cache.persistence.tree.io.SimpleDataPageIO; -import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler; import org.apache.ignite.internal.processors.failure.FailureProcessor; import org.apache.ignite.internal.util.lang.GridCursor; @@ -79,8 +73,6 @@ import org.jetbrains.annotations.NotNull; import static org.apache.ignite.internal.pagemem.PageIdAllocator.FLAG_DATA; import static org.apache.ignite.internal.pagemem.PageIdAllocator.OLD_METASTORE_PARTITION; -import static org.apache.ignite.internal.pagemem.PageIdUtils.itemId; -import static org.apache.ignite.internal.pagemem.PageIdUtils.pageId; /** * General purpose key-value local-only storage. @@ -104,7 +96,6 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { /** Temporary metastorage buffer size (file). */ private static final int TEMPORARY_METASTORAGE_BUFFER_SIZE = 1024 * 1024; - /** */ private final IgniteWriteAheadLogManager wal; @@ -136,7 +127,7 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { private RootPage reuseListRoot; /** */ - private FreeListImpl freeList; + private PartitionMetaStorageImpl partStorage; /** */ private SortedMap lastUpdates; @@ -245,14 +236,18 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { getOrAllocateMetas(partId = PageIdAllocator.METASTORE_PARTITION); if (!empty) { - freeList = new FreeListImpl(METASTORAGE_CACHE_ID, "metastorage", + partStorage = new PartitionMetaStorageImpl(METASTORAGE_CACHE_ID, "metastorage", regionMetrics, dataRegion, null, wal, reuseListRoot.pageId().pageId(), - reuseListRoot.isAllocated()); + reuseListRoot.isAllocated()) { + @Override protected long allocatePageNoReuse() throws IgniteCheckedException { + return pageMem.allocatePage(grpId, partId, FLAG_DATA); + } + }; - MetastorageRowStore rowStore = new MetastorageRowStore(freeList, db); + MetastorageRowStore rowStore = new MetastorageRowStore(partStorage, db); tree = new MetastorageTree(METASTORAGE_CACHE_ID, dataRegion.pageMemory(), wal, rmvId, - freeList, rowStore, treeRoot.pageId().pageId(), treeRoot.isAllocated(), failureProcessor, partId); + partStorage, rowStore, treeRoot.pageId().pageId(), treeRoot.isAllocated(), failureProcessor, partId); if (!readOnly) ((GridCacheDatabaseSharedManager)db).addCheckpointListener(this); @@ -578,14 +573,14 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { Executor executor = ctx.executor(); if (executor == null) { - freeList.saveMetadata(); + partStorage.saveMetadata(); saveStoreMetadata(); } else { executor.execute(() -> { try { - freeList.saveMetadata(); + partStorage.saveMetadata(); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -605,7 +600,7 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { /** {@inheritDoc} */ @Override public void beforeCheckpointBegin(Context ctx) throws IgniteCheckedException { - freeList.saveMetadata(); + partStorage.saveMetadata(); } /** {@inheritDoc} */ @@ -663,108 +658,6 @@ public class MetaStorage implements DbCheckpointListener, ReadWriteMetastorage { } } - /** */ - public class FreeListImpl extends AbstractFreeList { - /** {@inheritDoc} */ - FreeListImpl(int cacheId, String name, DataRegionMetricsImpl regionMetrics, DataRegion dataRegion, - ReuseList reuseList, - IgniteWriteAheadLogManager wal, long metaPageId, boolean initNew) throws IgniteCheckedException { - super(cacheId, name, regionMetrics, dataRegion, reuseList, wal, metaPageId, initNew); - } - - /** {@inheritDoc} */ - @Override public IOVersions> ioVersions() { - return SimpleDataPageIO.VERSIONS; - } - - /** {@inheritDoc} */ - @Override protected long allocatePageNoReuse() throws IgniteCheckedException { - return pageMem.allocatePage(grpId, partId, FLAG_DATA); - } - - /** - * Read row from data pages. - */ - final MetastorageDataRow readRow(String key, long link) - throws IgniteCheckedException { - assert link != 0 : "link"; - - long nextLink = link; - IncompleteObject incomplete = null; - int size = 0; - - boolean first = true; - - do { - final long pageId = pageId(nextLink); - - final long page = pageMem.acquirePage(grpId, pageId); - - try { - long pageAddr = pageMem.readLock(grpId, pageId, page); // Non-empty data page must not be recycled. - - assert pageAddr != 0L : nextLink; - - try { - SimpleDataPageIO io = (SimpleDataPageIO)ioVersions().forPage(pageAddr); - - //MetaStorage never encrypted so realPageSize == pageSize. - DataPagePayload data = io.readPayload(pageAddr, itemId(nextLink), pageMem.pageSize()); - - nextLink = data.nextLink(); - - if (first) { - if (nextLink == 0) { - // Fast path for a single page row. - return new MetastorageDataRow(link, key, SimpleDataPageIO.readPayload(pageAddr + data.offset())); - } - - first = false; - } - - ByteBuffer buf = pageMem.pageBuffer(pageAddr); - - buf.position(data.offset()); - buf.limit(data.offset() + data.payloadSize()); - - if (size == 0) { - if (buf.remaining() >= 4 && incomplete == null) { - // Just read size. - size = buf.getInt(); - incomplete = new IncompleteObject(new byte[size]); - } - else { - if (incomplete == null) - incomplete = new IncompleteObject(new byte[4]); - - incomplete.readData(buf); - - if (incomplete.isReady()) { - size = ByteBuffer.wrap(incomplete.data()).order(buf.order()).getInt(); - incomplete = new IncompleteObject(new byte[size]); - } - } - } - - if (size != 0 && buf.remaining() > 0) - incomplete.readData(buf); - } - finally { - pageMem.readUnlock(grpId, pageId, page); - } - } - finally { - pageMem.releasePage(grpId, pageId, page); - } - } - while (nextLink != 0); - - assert incomplete.isReady(); - - return new MetastorageDataRow(link, key, incomplete.data()); - } - } - /** * Temporary storage internal */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java index 2d7b0a6..a84924a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageDataRow.java @@ -17,34 +17,28 @@ package org.apache.ignite.internal.processors.cache.persistence.metastorage; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.PageIdAllocator; -import org.apache.ignite.internal.processors.cache.persistence.Storable; +import org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; /** * */ -public class MetastorageDataRow implements MetastorageSearchRow, Storable { - /** */ - private long link; - +public class MetastorageDataRow extends SimpleDataRow implements MetastorageSearchRow { /** */ private String key; /** */ - private byte[] value; - - /** */ - public MetastorageDataRow(long link, String key, byte[] value) { - this.link = link; + public MetastorageDataRow(long link, String key, byte[] val) { + super(link, MetaStorage.PRESERVE_LEGACY_METASTORAGE_PARTITION_ID ? + PageIdAllocator.OLD_METASTORE_PARTITION: PageIdAllocator.METASTORE_PARTITION, val); this.key = key; - this.value = value; } /** */ - public MetastorageDataRow(String key, byte[] value) { - this.key = key; - this.value = value; + public MetastorageDataRow(String key, byte[] val) { + this(0, key, val); } /** @@ -55,49 +49,17 @@ public class MetastorageDataRow implements MetastorageSearchRow, Storable { } /** {@inheritDoc} */ - @Override - public int hash() { + @Override public int hash() { return key.hashCode(); } /** {@inheritDoc} */ - @Override - public int partition() { - return MetaStorage.PRESERVE_LEGACY_METASTORAGE_PARTITION_ID ? PageIdAllocator.OLD_METASTORE_PARTITION: PageIdAllocator.METASTORE_PARTITION; - } - - /** {@inheritDoc} */ - @Override public int size() throws IgniteCheckedException { - return 4 + value().length; - } - - /** {@inheritDoc} */ - @Override public int headerSize() { - return 0; - } - - /** {@inheritDoc} */ - @Override - public void link(long link) { - this.link = link; - } - - /** {@inheritDoc} */ - @Override - public long link() { - return link; - } - - /** - * @return Value. - */ - public byte[] value() { - return value; + @Override public IOVersions ioVersions() { + return MetastoreDataPageIO.VERSIONS; } /** {@inheritDoc} */ - @Override - public String toString() { + @Override public String toString() { return "key=" + key; } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageRowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageRowStore.java index c482a94..ccc55dc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageRowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastorageRowStore.java @@ -19,7 +19,7 @@ package org.apache.ignite.internal.processors.cache.persistence.metastorage; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager; -import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList; +import org.apache.ignite.internal.processors.cache.persistence.partstorage.PartitionMetaStorage; import org.apache.ignite.internal.stat.IoStatisticsHolderNoOp; /** @@ -27,14 +27,14 @@ import org.apache.ignite.internal.stat.IoStatisticsHolderNoOp; */ public class MetastorageRowStore { /** */ - private final FreeList freeList; + private final PartitionMetaStorage partStorage; /** */ protected final IgniteCacheDatabaseSharedManager db; /** */ - public MetastorageRowStore(FreeList freeList, IgniteCacheDatabaseSharedManager db) { - this.freeList = freeList; + public MetastorageRowStore(PartitionMetaStorage partStorage, IgniteCacheDatabaseSharedManager db) { + this.partStorage = partStorage; this.db = db; } @@ -43,7 +43,7 @@ public class MetastorageRowStore { * @return Data row. */ public MetastorageDataRow dataRow(String key, long link) throws IgniteCheckedException { - return ((MetaStorage.FreeListImpl)freeList).readRow(key, link); + return new MetastorageDataRow(link, key, partStorage.readRow(link)); } /** @@ -55,7 +55,7 @@ public class MetastorageRowStore { db.checkpointReadLock(); try { - freeList.removeDataRowByLink(link, IoStatisticsHolderNoOp.INSTANCE); + partStorage.removeDataRowByLink(link, IoStatisticsHolderNoOp.INSTANCE); } finally { db.checkpointReadUnlock(); @@ -70,28 +70,10 @@ public class MetastorageRowStore { db.checkpointReadLock(); try { - freeList.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); + partStorage.insertDataRow(row, IoStatisticsHolderNoOp.INSTANCE); } finally { db.checkpointReadUnlock(); } } - - /** - * @param link Row link. - * @param row New row data. - * @return {@code True} if was able to update row. - * @throws IgniteCheckedException If failed. - */ - public boolean updateRow(long link, MetastorageDataRow row) throws IgniteCheckedException { - return freeList.updateDataRow(link, row, IoStatisticsHolderNoOp.INSTANCE); - } - - /** - * @return Free list. - */ - public FreeList freeList() { - return freeList; - } - } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastoreDataPageIO.java similarity index 52% copy from modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java copy to modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastoreDataPageIO.java index 133f0a1..0ac0915 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetastoreDataPageIO.java @@ -15,38 +15,23 @@ * limitations under the License. */ -package org.apache.ignite.internal.processors.cache.persistence; +package org.apache.ignite.internal.processors.cache.persistence.metastorage; -import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.SimpleDataPageIO; /** - * Simple interface for data, store in some RowStore. */ -public interface Storable { - /** - * @param link Link for this row. - */ - public void link(long link); - - /** - * @return Link for this row. - */ - public long link(); - - /** - * @return Partition. - */ - public int partition(); - - /** - * @return Row size in page. - * @throws IgniteCheckedException If failed. - */ - public int size() throws IgniteCheckedException; +public class MetastoreDataPageIO extends SimpleDataPageIO { + /** */ + public static final IOVersions VERSIONS = new IOVersions<>( + new MetastoreDataPageIO(1) + ); /** - * @return Row header size in page. Header is indivisible part of row - * which is entirely available on the very first page followed by the row link. + * @param ver Version. */ - public int headerSize(); + public MetastoreDataPageIO(int ver) { + super(T_DATA_METASTORAGE, ver); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorage.java similarity index 51% copy from modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java copy to modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorage.java index 133f0a1..0dbd5f4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/Storable.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorage.java @@ -15,38 +15,37 @@ * limitations under the License. */ -package org.apache.ignite.internal.processors.cache.persistence; +package org.apache.ignite.internal.processors.cache.persistence.partstorage; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.processors.cache.persistence.Storable; +import org.apache.ignite.internal.stat.IoStatisticsHolder; /** - * Simple interface for data, store in some RowStore. + * Provides a way to associate any {@link Storable} implementation as partition metadata. */ -public interface Storable { +public interface PartitionMetaStorage { /** - * @param link Link for this row. - */ - public void link(long link); - - /** - * @return Link for this row. + * Read row data by link as byte array. + * @param link Link. + * @throws IgniteCheckedException If failed. */ - public long link(); + public byte[] readRow(long link) throws IgniteCheckedException; /** - * @return Partition. + * @param row Row. + * @param statHolder Stat holder. */ - public int partition(); + public void insertDataRow(T row, IoStatisticsHolder statHolder) throws IgniteCheckedException; /** - * @return Row size in page. + * @param link Row link. * @throws IgniteCheckedException If failed. */ - public int size() throws IgniteCheckedException; + public void removeDataRowByLink(long link, IoStatisticsHolder statHolder) throws IgniteCheckedException; /** - * @return Row header size in page. Header is indivisible part of row - * which is entirely available on the very first page followed by the row link. + * Saves storage metadata. */ - public int headerSize(); + public void saveMetadata() throws IgniteCheckedException; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorageImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorageImpl.java new file mode 100644 index 0000000..f078f2c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/partstorage/PartitionMetaStorageImpl.java @@ -0,0 +1,140 @@ +/* + * 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.partstorage; + +import java.nio.ByteBuffer; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageUtils; +import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager; +import org.apache.ignite.internal.processors.cache.IncompleteObject; +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.freelist.AbstractFreeList; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.AbstractDataPageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPagePayload; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; +import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; + +import static org.apache.ignite.internal.pagemem.PageIdUtils.itemId; +import static org.apache.ignite.internal.pagemem.PageIdUtils.pageId; + +/** + */ +public class PartitionMetaStorageImpl extends AbstractFreeList implements PartitionMetaStorage { + /** + * @param cacheId Cache id. + * @param name Name. + * @param memMetrics Mem metrics. + * @param memPlc Mem policy. + * @param reuseList Reuse list. + * @param wal Wal. + * @param metaPageId Meta page id. + * @param initNew Initialize new. + */ + public PartitionMetaStorageImpl(int cacheId, String name, + DataRegionMetricsImpl memMetrics, + DataRegion memPlc, + ReuseList reuseList, + IgniteWriteAheadLogManager wal, long metaPageId, boolean initNew) throws IgniteCheckedException { + super(cacheId, name, memMetrics, memPlc, reuseList, wal, metaPageId, initNew); + } + + /** + * Read row as byte array from data pages. + */ + @Override public final byte[] readRow(long link) throws IgniteCheckedException { + assert link != 0 : "link"; + + long nextLink = link; + IncompleteObject incomplete = null; + int size = 0; + + boolean first = true; + + do { + final long pageId = pageId(nextLink); + + final long page = pageMem.acquirePage(grpId, pageId); + + try { + long pageAddr = pageMem.readLock(grpId, pageId, page); // Non-empty data page must not be recycled. + + assert pageAddr != 0L : nextLink; + + try { + AbstractDataPageIO io = PageIO.getPageIO(pageAddr); + + //MetaStorage never encrypted so realPageSize == pageSize. + DataPagePayload data = io.readPayload(pageAddr, itemId(nextLink), pageMem.pageSize()); + + nextLink = data.nextLink(); + + if (first) { + if (nextLink == 0) { + long payloadAddr = pageAddr + data.offset(); + + // Fast path for a single page row. + return PageUtils.getBytes(payloadAddr, 4, PageUtils.getInt(payloadAddr, 0)); + } + + first = false; + } + + ByteBuffer buf = pageMem.pageBuffer(pageAddr); + + buf.position(data.offset()); + buf.limit(data.offset() + data.payloadSize()); + + if (size == 0) { + if (buf.remaining() >= 4 && incomplete == null) { + // Just read size. + size = buf.getInt(); + incomplete = new IncompleteObject(new byte[size]); + } + else { + if (incomplete == null) + incomplete = new IncompleteObject(new byte[4]); + + incomplete.readData(buf); + + if (incomplete.isReady()) { + size = ByteBuffer.wrap(incomplete.data()).order(buf.order()).getInt(); + incomplete = new IncompleteObject(new byte[size]); + } + } + } + + if (size != 0 && buf.remaining() > 0) + incomplete.readData(buf); + } + finally { + pageMem.readUnlock(grpId, pageId, page); + } + } + finally { + pageMem.releasePage(grpId, pageId, page); + } + } + while (nextLink != 0); + + assert incomplete.isReady(); + + return incomplete.data(); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java index 54d9816..c131a1e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java @@ -3775,6 +3775,7 @@ public abstract class BPlusTree extends DataStructure implements break; case NOOP: + case IN_PLACE: return; default: diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/AbstractDataPageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/AbstractDataPageIO.java index 78752bb..a2e03e9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/AbstractDataPageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/AbstractDataPageIO.java @@ -39,7 +39,6 @@ import static org.apache.ignite.internal.util.GridUnsafe.bufferAddress; * Data pages IO. */ public abstract class AbstractDataPageIO extends PageIO implements CompactablePageIO { - /** */ private static final int SHOW_ITEM = 0b0001; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java index dcf1acd..fafea22 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java @@ -31,6 +31,7 @@ import org.apache.ignite.internal.processors.cache.persistence.IndexStorageImpl; import org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListMetaIO; import org.apache.ignite.internal.processors.cache.persistence.freelist.io.PagesListNodeIO; import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageTree; +import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastoreDataPageIO; import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler; import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageLockListener; import org.apache.ignite.internal.processors.cache.tree.CacheIdAwareDataInnerIO; @@ -251,6 +252,9 @@ public abstract class PageIO { /** */ public static final short T_TX_LOG_INNER = 31; + /** */ + public static final short T_DATA_PART = 32; + /** Index for payload == 1. */ public static final short T_H2_EX_REF_LEAF_START = 10_000; @@ -667,6 +671,9 @@ public abstract class PageIO { return (Q)TrackingPageIO.VERSIONS.forVersion(ver); case T_DATA_METASTORAGE: + return (Q)MetastoreDataPageIO.VERSIONS.forVersion(ver); + + case T_DATA_PART: return (Q)SimpleDataPageIO.VERSIONS.forVersion(ver); default: diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIO.java index 6a81057..c86a64a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIO.java @@ -194,6 +194,40 @@ public class PagePartitionMetaIO extends PageMetaIO { "this PagePartitionMetaIO version: ver=" + getVersion()); } + /** + * @param pageAddr Page address. + */ + public long getPartitionMetaStoreReuseListRoot(long pageAddr) { + throw new UnsupportedOperationException("Partition metastore is not supported by " + + "this PagePartitionMetaIO version: ver=" + getVersion()); + } + + /** + * @param pageAddr Page address. + * @param listRoot List root. + */ + public void setPartitionMetaStoreReuseListRoot(long pageAddr, long listRoot) { + throw new UnsupportedOperationException("Partition metastore is not supported by " + + "this PagePartitionMetaIO version: ver=" + getVersion()); + } + + /** + * @param pageAddr Page address. + */ + public long getGapsLink(long pageAddr) { + throw new UnsupportedOperationException("Gaps link is not supported by " + + "this PagePartitionMetaIO version: ver=" + getVersion()); + } + + /** + * @param pageAddr Page address. + * @param link Link. + */ + public boolean setGapsLink(long pageAddr, long link) { + throw new UnsupportedOperationException("Gaps link is not supported by " + + "this PagePartitionMetaIO version: ver=" + getVersion()); + } + /** {@inheritDoc} */ @Override protected void printPage(long pageAddr, int pageSize, GridStringBuilder sb) throws IgniteCheckedException { super.printPage(pageAddr, pageSize, sb); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIOV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIOV2.java index 220ff83..37b7243 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIOV2.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionMetaIOV2.java @@ -31,6 +31,12 @@ public class PagePartitionMetaIOV2 extends PagePartitionMetaIO { /** */ private static final int PENDING_TREE_ROOT_OFF = PagePartitionMetaIO.END_OF_PARTITION_PAGE_META; + /** */ + private static final int PART_META_REUSE_LIST_ROOT_OFF = PENDING_TREE_ROOT_OFF + 8; + + /** */ + private static final int GAPS_LINK = PART_META_REUSE_LIST_ROOT_OFF + 8; + /** * @param ver Version. */ @@ -43,6 +49,8 @@ public class PagePartitionMetaIOV2 extends PagePartitionMetaIO { super.initNewPage(pageAddr, pageId, pageSize); setPendingTreeRoot(pageAddr, 0L); + setPartitionMetaStoreReuseListRoot(pageAddr, 0L); + setGapsLink(pageAddr, 0); } /** {@inheritDoc} */ @@ -51,8 +59,44 @@ public class PagePartitionMetaIOV2 extends PagePartitionMetaIO { } /** {@inheritDoc} */ - @Override public void setPendingTreeRoot(long pageAddr, long treeRoot) { - PageUtils.putLong(pageAddr, PENDING_TREE_ROOT_OFF, treeRoot); + @Override public void setPendingTreeRoot(long pageAddr, long listRoot) { + PageUtils.putLong(pageAddr, PENDING_TREE_ROOT_OFF, listRoot); + } + + /** + * @param pageAddr Page address. + */ + @Override public long getPartitionMetaStoreReuseListRoot(long pageAddr) { + return PageUtils.getLong(pageAddr, PART_META_REUSE_LIST_ROOT_OFF); + } + + /** + * @param pageAddr Page address. + * @param listRoot List root. + */ + @Override public void setPartitionMetaStoreReuseListRoot(long pageAddr, long listRoot) { + PageUtils.putLong(pageAddr, PART_META_REUSE_LIST_ROOT_OFF, listRoot); + } + + /** + * @param pageAddr Page address. + * @return Partition size. + */ + public long getGapsLink(long pageAddr) { + return PageUtils.getLong(pageAddr, GAPS_LINK); + } + + /** + * @param pageAddr Page address. + * @param link Link. + */ + public boolean setGapsLink(long pageAddr, long link) { + if (getGapsLink(pageAddr) == link) + return false; + + PageUtils.putLong(pageAddr, GAPS_LINK, link); + + return true; } /** {@inheritDoc} */ @@ -72,6 +116,7 @@ public class PagePartitionMetaIOV2 extends PagePartitionMetaIO { sb.a(",\n\tglobalRemoveId=").a(getGlobalRemoveId(pageAddr)); sb.a(",\n\tpartitionState=").a(state).a("(").a(GridDhtPartitionState.fromOrdinal(state)).a(")"); sb.a(",\n\tcountersPageId=").a(getCountersPageId(pageAddr)); + sb.a(",\n\tcntrUpdDataPageId=").a(getGapsLink(pageAddr)); sb.a("\n]"); } @@ -86,5 +131,7 @@ public class PagePartitionMetaIOV2 extends PagePartitionMetaIO { PageIO.setVersion(pageAddr, getVersion()); setPendingTreeRoot(pageAddr, 0); + setPartitionMetaStoreReuseListRoot(pageAddr, 0); + setGapsLink(pageAddr, 0); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/SimpleDataPageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/SimpleDataPageIO.java index 14489b7..716f8be 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/SimpleDataPageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/SimpleDataPageIO.java @@ -20,13 +20,13 @@ package org.apache.ignite.internal.processors.cache.persistence.tree.io; import java.nio.ByteBuffer; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.PageUtils; -import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageDataRow; +import org.apache.ignite.internal.processors.cache.persistence.freelist.SimpleDataRow; import org.apache.ignite.internal.util.GridStringBuilder; /** - * Data pages IO for Metastorage. + * Data pages IO for writing binary arrays. */ -public class SimpleDataPageIO extends AbstractDataPageIO { +public class SimpleDataPageIO extends AbstractDataPageIO { /** */ public static final IOVersions VERSIONS = new IOVersions<>( new SimpleDataPageIO(1) @@ -36,13 +36,21 @@ public class SimpleDataPageIO extends AbstractDataPageIO { * @param ver Page format version. */ public SimpleDataPageIO(int ver) { - super(T_DATA_METASTORAGE, ver); + super(T_DATA_PART, ver); + } + + /** + * Constructor is intended for extending types. + * @param type IO type. + * @param ver Page format version. + */ + public SimpleDataPageIO(int type, int ver) { + super(type, ver); } /** {@inheritDoc} */ - @Override - protected void writeFragmentData( - final MetastorageDataRow row, + @Override protected void writeFragmentData( + final SimpleDataRow row, final ByteBuffer buf, final int rowOff, final int payloadSize @@ -65,7 +73,7 @@ public class SimpleDataPageIO extends AbstractDataPageIO { } /** */ - private int writeSizeFragment(final MetastorageDataRow row, final ByteBuffer buf, final int rowOff, + private int writeSizeFragment(final SimpleDataRow row, final ByteBuffer buf, final int rowOff, final int payloadSize) { final int size = 4; @@ -89,12 +97,11 @@ public class SimpleDataPageIO extends AbstractDataPageIO { } /** {@inheritDoc} */ - @Override - protected void writeRowData( + @Override protected void writeRowData( long pageAddr, int dataOff, int payloadSize, - MetastorageDataRow row, + SimpleDataRow row, boolean newRow ) throws IgniteCheckedException { long addr = pageAddr + dataOff; @@ -106,12 +113,6 @@ public class SimpleDataPageIO extends AbstractDataPageIO { PageUtils.putBytes(addr, 6, row.value()); } - public static byte[] readPayload(long link) { - int size = PageUtils.getInt(link, 0); - - return PageUtils.getBytes(link, 4, size); - } - /** {@inheritDoc} */ @Override protected void printPage(long addr, int pageSize, GridStringBuilder sb) throws IgniteCheckedException { sb.a("SimpleDataPageIO [\n"); 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 5ab1bf3..ff980af 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 @@ -26,6 +26,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.InitNewPageRecord; import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO; import org.apache.ignite.internal.stat.IoStatisticsHolder; import org.apache.ignite.internal.util.GridUnsafe; +import org.jetbrains.annotations.Nullable; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; @@ -463,7 +464,7 @@ public abstract class PageHandler { long pageId, long page, IgniteWriteAheadLogManager wal, - Boolean walPlc) { + @Nullable Boolean walPlc) { // If the page is clean, then it is either newly allocated or just after checkpoint. // In both cases we have to write full page contents to WAL. return wal != null && !wal.isAlwaysWriteFullPages() && walPlc != TRUE && !wal.disabled(cacheId) && diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java index 86924c6..2831d87 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java @@ -917,7 +917,7 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl if (hnd != null) end = hnd.position(); - return new RecordsIterator( + RecordsIterator iter = new RecordsIterator( cctx, walArchiveDir, walWorkDir, @@ -932,6 +932,17 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl segmentAware, segmentRouter, lockedSegmentFileInputFactory); + + try { + iter.init(); // Make sure iterator is closed on any error. + } + catch (Throwable t) { + iter.close(); + + throw t; + } + + return iter; } /** {@inheritDoc} */ @@ -2673,10 +2684,6 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl this.decompressor = decompressor; this.segmentRouter = segmentRouter; this.segmentAware = segmentAware; - - init(); - - advance(); } /** {@inheritDoc} */ @@ -2760,6 +2767,8 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl if (log.isDebugEnabled()) log.debug("Initialized WAL cursor [start=" + start + ", end=" + end + ", curWalSegmIdx=" + curWalSegmIdx + ']'); + + advance(); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java index 65f0aae..b6d20dc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java @@ -60,6 +60,7 @@ public final class RecordTypes { DELTA_TYPE_SET.add(WALRecord.RecordType.PAGES_LIST_REMOVE_PAGE); DELTA_TYPE_SET.add(WALRecord.RecordType.META_PAGE_INIT); DELTA_TYPE_SET.add(WALRecord.RecordType.PARTITION_META_PAGE_UPDATE_COUNTERS); + DELTA_TYPE_SET.add(WALRecord.RecordType.PARTITION_META_PAGE_UPDATE_COUNTERS_V2); DELTA_TYPE_SET.add(WALRecord.RecordType.TRACKING_PAGE_DELTA); DELTA_TYPE_SET.add(WALRecord.RecordType.META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID); DELTA_TYPE_SET.add(WALRecord.RecordType.META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java index 705cc38..ec68972 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java @@ -70,6 +70,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdateLastSuc import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdateLastSuccessfulSnapshotId; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdateNextSnapshotId; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdatePartitionDataRecord; +import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdatePartitionDataRecordV2; import org.apache.ignite.internal.pagemem.wal.record.delta.NewRootInitRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.PageListMetaResetCountRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.PagesListAddPageRecord; @@ -374,6 +375,10 @@ public class RecordDataV1Serializer implements RecordDataSerializer { return /*cache ID*/4 + /*page ID*/8 + /*upd cntr*/8 + /*rmv id*/8 + /*part size*/4 + /*counters page id*/8 + /*state*/ 1 + /*allocatedIdxCandidate*/ 4; + case PARTITION_META_PAGE_UPDATE_COUNTERS_V2: + return /*cache ID*/4 + /*page ID*/8 + /*upd cntr*/8 + /*rmv id*/8 + /*part size*/4 + /*counters page id*/8 + /*state*/ 1 + + /*allocatedIdxCandidate*/ 4 + /*link*/ 8; + case MEMORY_RECOVERY: return 8; @@ -597,17 +602,12 @@ public class RecordDataV1Serializer implements RecordDataSerializer { break; case PARTITION_META_PAGE_UPDATE_COUNTERS: - cacheId = in.readInt(); - pageId = in.readLong(); + res = new MetaPageUpdatePartitionDataRecord(in); - long updCntr = in.readLong(); - long rmvId = in.readLong(); - int partSize = in.readInt(); - long countersPageId = in.readLong(); - byte state = in.readByte(); - int allocatedIdxCandidate = in.readInt(); + break; - res = new MetaPageUpdatePartitionDataRecord(cacheId, pageId, updCntr, rmvId, partSize, countersPageId, state, allocatedIdxCandidate); + case PARTITION_META_PAGE_UPDATE_COUNTERS_V2: + res = new MetaPageUpdatePartitionDataRecordV2(in); break; @@ -950,7 +950,7 @@ public class RecordDataV1Serializer implements RecordDataSerializer { int dstIdx = in.readUnsignedShort(); long srcPageId = in.readLong(); int srcIdx = in.readUnsignedShort(); - rmvId = in.readLong(); + long rmvId = in.readLong(); res = new InnerReplaceRecord<>(cacheId, pageId, dstIdx, srcPageId, srcIdx, rmvId); @@ -1112,7 +1112,7 @@ public class RecordDataV1Serializer implements RecordDataSerializer { partId = in.readInt(); - state = in.readByte(); + byte state = in.readByte(); long updateCntr = in.readLong(); @@ -1201,17 +1201,8 @@ public class RecordDataV1Serializer implements RecordDataSerializer { break; case PARTITION_META_PAGE_UPDATE_COUNTERS: - MetaPageUpdatePartitionDataRecord partDataRec = (MetaPageUpdatePartitionDataRecord)rec; - - buf.putInt(partDataRec.groupId()); - buf.putLong(partDataRec.pageId()); - - buf.putLong(partDataRec.updateCounter()); - buf.putLong(partDataRec.globalRemoveId()); - buf.putInt(partDataRec.partitionSize()); - buf.putLong(partDataRec.countersPageId()); - buf.put(partDataRec.state()); - buf.putInt(partDataRec.allocatedIndexCandidate()); + case PARTITION_META_PAGE_UPDATE_COUNTERS_V2: + ((MetaPageUpdatePartitionDataRecord)rec).toBytes(buf); break; @@ -1690,7 +1681,7 @@ public class RecordDataV1Serializer implements RecordDataSerializer { buf.put(partMetaStateRecord.state()); - buf.putLong(partMetaStateRecord.updateCounter()); + buf.putLong(0); break; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java index ec45a06..3063a25 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java @@ -38,6 +38,7 @@ import org.apache.ignite.internal.pagemem.wal.record.MvccDataEntry; import org.apache.ignite.internal.pagemem.wal.record.MvccDataRecord; import org.apache.ignite.internal.pagemem.wal.record.MvccTxRecord; import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot; +import org.apache.ignite.internal.pagemem.wal.record.RollbackRecord; import org.apache.ignite.internal.pagemem.wal.record.SnapshotRecord; import org.apache.ignite.internal.pagemem.wal.record.TxRecord; import org.apache.ignite.internal.pagemem.wal.record.WALRecord; @@ -111,6 +112,9 @@ public class RecordDataV2Serializer extends RecordDataV1Serializer { case MVCC_TX_RECORD: return txRecordSerializer.size((MvccTxRecord)rec); + case ROLLBACK_TX_RECORD: + return 4 + 4 + 8 + 8; + default: return super.plainSize(rec); } @@ -206,6 +210,14 @@ public class RecordDataV2Serializer extends RecordDataV1Serializer { case MVCC_TX_RECORD: return txRecordSerializer.readMvccTx(in); + case ROLLBACK_TX_RECORD: + int grpId = in.readInt(); + int partId = in.readInt(); + long start = in.readLong(); + long range = in.readLong(); + + return new RollbackRecord(grpId, partId, start, range); + default: return super.readPlainRecord(type, in, encrypted, recordSize); } @@ -288,6 +300,16 @@ public class RecordDataV2Serializer extends RecordDataV1Serializer { break; + case ROLLBACK_TX_RECORD: + RollbackRecord rb = (RollbackRecord)rec; + + buf.putInt(rb.groupId()); + buf.putInt(rb.partitionId()); + buf.putLong(rb.start()); + buf.putLong(rb.range()); + + break; + default: super.writePlainRecord(rec, buf); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEventBuffer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEventBuffer.java index c707c72..82400f2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEventBuffer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEventBuffer.java @@ -114,9 +114,10 @@ public class CacheContinuousQueryEventBuffer { } /** + * @param backup {@code True} if backup context. * @return Initial partition counter. */ - protected long currentPartitionCounter() { + protected long currentPartitionCounter(boolean backup) { return 0; } @@ -153,7 +154,7 @@ public class CacheContinuousQueryEventBuffer { Object res = null; for (;;) { - batch = initBatch(entry.topologyVersion()); + batch = initBatch(entry.topologyVersion(), backup); if (batch == null || cntr < batch.startCntr) { if (backup) { @@ -185,7 +186,7 @@ public class CacheContinuousQueryEventBuffer { res = processPending(res, batch, backup); - batch0 = initBatch(entry.topologyVersion()); + batch0 = initBatch(entry.topologyVersion(), backup); } while (batch != batch0); } @@ -195,16 +196,17 @@ public class CacheContinuousQueryEventBuffer { /** * @param topVer Current event topology version. + * @param backup {@code True} if backup entry. * @return Current batch. */ - @Nullable private Batch initBatch(AffinityTopologyVersion topVer) { + private Batch initBatch(AffinityTopologyVersion topVer, boolean backup) { Batch batch = curBatch.get(); if (batch != null) return batch; for (;;) { - long curCntr = currentPartitionCounter(); + long curCntr = currentPartitionCounter(backup); if (curCntr == -1) return null; @@ -483,4 +485,4 @@ public class CacheContinuousQueryEventBuffer { return res; } } -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java index 7f9b918..d8737bd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheAdapter; import org.apache.ignite.internal.processors.cache.GridCacheAffinityManager; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeploymentManager; +import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicAbstractUpdateFuture; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; import org.apache.ignite.internal.processors.cache.query.CacheQueryType; @@ -1106,13 +1107,14 @@ public class CacheContinuousQueryHandler implements GridContinuousHandler if (buf == null) { buf = new CacheContinuousQueryEventBuffer(part) { - @Override protected long currentPartitionCounter() { + @Override protected long currentPartitionCounter(boolean backup) { GridDhtLocalPartition locPart = cctx.topology().localPartition(part, null, false); if (locPart == null) return -1L; - return locPart.updateCounter(); + // Use HWM for primary, LWM for backup. + return backup ? locPart.updateCounter() : locPart.reservedCounter(); } }; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java index 7d0f988..a105a2f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java @@ -40,6 +40,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.distributed.IgniteExternalizableExpiryPolicy; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.util.lang.GridAbsClosureX; import org.apache.ignite.internal.util.lang.GridPeerDeployAware; import org.apache.ignite.internal.util.tostring.GridToStringBuilder; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -212,6 +213,11 @@ public class IgniteTxEntry implements GridPeerDeployAware, Message { /** */ private GridCacheVersion serReadVer; + /** */ + @GridDirectTransient + @GridToStringExclude + private transient @Nullable GridAbsClosureX cqNotifyC; + /** * Required by {@link Externalizable} */ @@ -1262,6 +1268,19 @@ public class IgniteTxEntry implements GridPeerDeployAware, Message { key.getClass() : val != null ? val.getClass() : getClass(); } + /** + */ + public GridAbsClosureX cqNotifyClosure() { + return cqNotifyC; + } + + /** + * @param clo Clo. + */ + public void cqNotifyClosure(GridAbsClosureX clo) { + cqNotifyC = clo; + } + /** {@inheritDoc} */ @Override public ClassLoader classLoader() { return deployClass().getClassLoader(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java index 719bf04..787fb97 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.UUID; import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.failure.FailureContext; @@ -30,6 +31,7 @@ import org.apache.ignite.failure.FailureType; import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.pagemem.wal.record.RollbackRecord; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection; import org.apache.ignite.internal.processors.cache.CacheObject; @@ -1352,8 +1354,14 @@ public class IgniteTxHandler { if (dhtTx != null) finish(nodeId, dhtTx, req); - else - applyPartitionsUpdatesCounters(req.updateCounters()); + else { + try { + applyPartitionsUpdatesCounters(req.updateCounters(), !req.commit(), false); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } if (nearTx != null) finish(nodeId, nearTx, req); @@ -1422,9 +1430,6 @@ public class IgniteTxHandler { // Complete remote candidates. tx.doneRemote(req.baseVersion(), null, null, null); - tx.setPartitionUpdateCounters( - req.partUpdateCounters() != null ? req.partUpdateCounters().array() : null); - tx.commitRemoteTx(); } else { @@ -1698,7 +1703,7 @@ public class IgniteTxHandler { if (log.isDebugEnabled()) log.debug("Attempt to start a completed transaction (will ignore): " + tx); - applyPartitionsUpdatesCounters(req.updateCounters()); + applyPartitionsUpdatesCounters(req.updateCounters(), true, false); return null; } @@ -1710,7 +1715,7 @@ public class IgniteTxHandler { ctx.tm().uncommitTx(tx); - applyPartitionsUpdatesCounters(req.updateCounters()); + applyPartitionsUpdatesCounters(req.updateCounters(), true, false); return null; } @@ -1720,8 +1725,13 @@ public class IgniteTxHandler { tx.transactionNodes(req.transactionNodes()); } - if (req.updateCounters() != null) - tx.txCounters(true).updateCounters(req.updateCounters()); + TxCounters txCounters = null; + + if (req.updateCounters() != null) { + txCounters = tx.txCounters(true); + + txCounters.updateCounters(req.updateCounters()); + } if (!tx.isSystemInvalidate()) { int idx = 0; @@ -1739,6 +1749,13 @@ public class IgniteTxHandler { try { tx.addWrite(entry, ctx.deploy().globalLoader()); + if (txCounters != null) { + Long cntr = txCounters.generateNextCounter(entry.cacheId(), entry.cached().partition()); + + if (cntr != null) // Counter is null if entry is no-op. + entry.updateCounter(cntr); + } + if (isNearEnabled(cacheCtx) && req.invalidateNearEntry(idx)) invalidateNearEntry(cacheCtx, entry.key(), req.version()); @@ -2198,7 +2215,12 @@ public class IgniteTxHandler { * @param req Request. */ private void processPartitionCountersRequest(UUID nodeId, PartitionCountersNeighborcastRequest req) { - applyPartitionsUpdatesCounters(req.updateCounters()); + try { + applyPartitionsUpdatesCounters(req.updateCounters(), true, false); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } try { ctx.io().send(nodeId, new PartitionCountersNeighborcastResponse(req.futId()), SYSTEM_POOL); @@ -2230,21 +2252,32 @@ public class IgniteTxHandler { } /** - * Applies partition counter updates for mvcc transactions. + * @param counters Counters. + */ + public void applyPartitionsUpdatesCounters(Iterable counters) + throws IgniteCheckedException { + applyPartitionsUpdatesCounters(counters, false, false); + } + + /** + * Applies partition counter updates for transactions. * * @param counters Counter values to be updated. + * @param rollback {@code True} if applied from rollbacks. */ - public void applyPartitionsUpdatesCounters(Iterable counters) { + public void applyPartitionsUpdatesCounters(Iterable counters, + boolean rollback, + boolean rollbackOnPrimary) throws IgniteCheckedException { if (counters == null) return; for (PartitionUpdateCountersMessage counter : counters) { GridCacheContext ctx0 = ctx.cacheContext(counter.cacheId()); - assert ctx0.mvccEnabled(); - GridDhtPartitionTopology top = ctx0.topology(); + AffinityTopologyVersion topVer = top.readyTopologyVersion(); + assert top != null; for (int i = 0; i < counter.size(); i++) { @@ -2255,8 +2288,29 @@ public class IgniteTxHandler { if (part != null && part.reserve()) { try { - if (part.state() != GridDhtPartitionState.RENTING) - part.updateCounter(counter.initialCounter(i), counter.updatesCount(i)); + if (part.state() != GridDhtPartitionState.RENTING) { // Check is actual only for backup node. + long start = counter.initialCounter(i); + long delta = counter.updatesCount(i); + + boolean updated = part.updateCounter(start, delta); + + // Need to log rolled back range for logical recovery. + if (updated && rollback) { + if (part.group().persistenceEnabled() && + part.group().walEnabled() && + !part.group().mvccEnabled()) { + RollbackRecord rec = new RollbackRecord(part.group().groupId(), part.id(), + start, delta); + + ctx.wal().log(rec); + } + + for (int cntr = 1; cntr <= delta; cntr++) { + ctx0.continuousQueries().skipUpdateCounter(null, part.id(), start + cntr, + topVer, rollbackOnPrimary); + } + } + } else invalid = true; } @@ -2272,7 +2326,7 @@ public class IgniteTxHandler { } if (invalid && log.isDebugEnabled()) - log.debug("Received partition update counters message for invalid partition: " + + log.debug("Received partition update counters message for invalid partition, ignoring: " + "[cacheId=" + counter.cacheId() + ", part=" + counter.partition(i) + "]"); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java index 26350b6..55376f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java @@ -57,7 +57,6 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheExpiryPolicy; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition; -import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal; import org.apache.ignite.internal.processors.cache.store.CacheStoreManager; @@ -95,6 +94,8 @@ import static org.apache.ignite.internal.processors.cache.GridCacheOperation.REA import static org.apache.ignite.internal.processors.cache.GridCacheOperation.RELOAD; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE; +import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.LOST; +import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_PRIMARY; import static org.apache.ignite.transactions.TransactionState.COMMITTED; @@ -431,7 +432,8 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig try { cctx.tm().prepareTx(this, entries); - calculatePartitionUpdateCounters(); + if (txState().mvccEnabled()) + calculatePartitionUpdateCounters(); } catch (IgniteCheckedException e) { throw e; @@ -451,7 +453,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig * pair (init, delta) values, where init - initial update counter, and delta - updates count made * by current transaction for a given partition. */ - private void calculatePartitionUpdateCounters() { + public void calculatePartitionUpdateCounters() { TxCounters counters = txCounters(false); if (counters != null && F.isEmpty(counters.updateCounters())) { @@ -468,9 +470,8 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig continue; PartitionUpdateCountersMessage msg = new PartitionUpdateCountersMessage(cacheId, partToCntrs.size()); - GridCacheContext ctx0 = cctx.cacheContext(cacheId); - assert ctx0 != null && ctx0.mvccEnabled(); + GridCacheContext ctx0 = cctx.cacheContext(cacheId); GridDhtPartitionTopology top = ctx0.topology(); @@ -490,7 +491,11 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig GridDhtLocalPartition part = top.localPartition(p); - assert part != null && part.state() == GridDhtPartitionState.OWNING; + // LOST state is possible if tx is started over LOST partition. + assert part != null && (part.state() == OWNING || part.state() == LOST): + part == null ? + "map=" + top.partitionMap(false) + ", lost=" + top.lostPartitions() : + "part=" + part.toString(); msg.add(p, part.getAndIncrementUpdateCounter(cntr), cntr); } @@ -577,6 +582,8 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig AffinityTopologyVersion topVer = topologyVersion(); + TxCounters txCounters = txCounters(false); + /* * Commit to cache. Note that for 'near' transaction we loop through all the entries. */ @@ -893,7 +900,15 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topologyVersion())); } } + } + + if (!txState.mvccEnabled() && txCounters != null) { + cctx.tm().txHandler().applyPartitionsUpdatesCounters(txCounters.updateCounters()); + for (IgniteTxEntry entry : commitEntries) { + if (entry.cqNotifyClosure() != null) + entry.cqNotifyClosure().applyx(); + } } // Apply cache sizes only for primary nodes. Update counters were applied on prepare state. @@ -1072,6 +1087,13 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig } if (DONE_FLAG_UPD.compareAndSet(this, 0, 1)) { + if (!txState.mvccEnabled()) { + TxCounters txCounters = txCounters(false); + + if (txCounters != null) + cctx.tm().txHandler().applyPartitionsUpdatesCounters(txCounters.updateCounters(), true, true); + } + cctx.tm().rollbackTx(this, clearThreadMap, skipCompletedVersions()); cctx.mvccCaching().onTxFinished(this, false); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java index c88c863..6f2d594 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java @@ -2128,8 +2128,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter { if (commit) tx.commitAsync().listen(new CommitListener(tx)); - else if (tx.mvccSnapshot() != null && !tx.local()) - // remote (backup) mvcc transaction sends partition counters to other backup transaction + else if (!tx.local()) + // remote (backup) transaction sends partition counters to other backup transaction on recovery rollback // in order to keep counters consistent neighborcastPartitionCountersAndRollback(tx); else diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxCounters.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxCounters.java index 515aeef..15c92f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxCounters.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxCounters.java @@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage; +import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; /** @@ -37,7 +38,7 @@ public class TxCounters { private final Map> updCntrsAcc = new HashMap<>(); /** Final update counters for cache partitions in the end of transaction */ - private volatile Collection updCntrs; + private volatile Map updCntrs; /** Counter tracking number of entries locked by tx. */ private final AtomicInteger lockCntr = new AtomicInteger(); @@ -68,14 +69,17 @@ public class TxCounters { * @param updCntrs Final update counters. */ public void updateCounters(Collection updCntrs) { - this.updCntrs = updCntrs; + this.updCntrs = U.newHashMap(updCntrs.size()); + + for (PartitionUpdateCountersMessage cntr : updCntrs) + this.updCntrs.put(cntr.cacheId(), cntr); } /** * @return Final update counters. */ @Nullable public Collection updateCounters() { - return updCntrs; + return updCntrs == null ? null : updCntrs.values(); } /** @@ -145,4 +149,19 @@ public class TxCounters { public int lockCounter() { return lockCntr.get(); } + + /** + * @param cacheId Cache id. + * @param partId Partition id. + * + * @return Counter or {@code null} if cache partition has not updates. + */ + public Long generateNextCounter(int cacheId, int partId) { + PartitionUpdateCountersMessage msg = updCntrs.get(cacheId); + + if (msg == null) + return null; + + return msg.nextCounter(partId); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java index f05e0e5..17d4be0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java @@ -44,6 +44,7 @@ import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteFeatures; import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.NodeStoppingException; import org.apache.ignite.internal.cluster.ClusterGroupAdapter; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration; @@ -385,7 +386,7 @@ public class GridClusterStateProcessor extends GridProcessorAdapter implements I GridChangeGlobalStateFuture fut = this.stateChangeFut.get(); if (fut != null) - fut.onDone(new IgniteCheckedException("Failed to wait for cluster state change, node is stopping.")); + fut.onDone(new NodeStoppingException("Failed to wait for cluster state change, node is stopping.")); super.onKernalStop(cancel); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/stat/IoStatisticsHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/stat/IoStatisticsHolder.java index 0c36820..5b7a57f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/stat/IoStatisticsHolder.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/stat/IoStatisticsHolder.java @@ -24,7 +24,6 @@ import java.util.Map; * Holder of IO statistics. */ public interface IoStatisticsHolder { - /** * Track logical read of given page. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteTree.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteTree.java index 9e854d2..140349a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteTree.java @@ -141,6 +141,9 @@ public interface IgniteTree { REMOVE, /** */ - PUT + PUT, + + /** */ + IN_PLACE } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 395705c..5d9d8da 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -9519,6 +9519,60 @@ public abstract class IgniteUtils { } /** + * Create a map with single key-value pair. + * + * @param k Key. + * @param v Value. + * @return Map. + */ + public static Map map(K k, V v) { + GridLeanMap map = new GridLeanMap<>(1); + + map.put(k, v); + + return map; + } + + /** + * Create a map with two key-value pairs. + * + * @param k1 Key 1. + * @param v1 Value 1. + * @param k2 Key 2. + * @param v2 Value 2. + * @return Map. + */ + public static Map map(K k1, V v1, K k2, V v2) { + GridLeanMap map = new GridLeanMap<>(2); + + map.put(k1, v1); + map.put(k2, v2); + + return map; + } + + /** + * Create a map with three key-value pairs. + * + * @param k1 Key 1. + * @param v1 Value 1. + * @param k2 Key 2. + * @param v2 Value 2. + * @param k3 Key 3. + * @param v3 Value 3. + * @return Map. + */ + public static Map map(K k1, V v1, K k2, V v2, K k3, V v3) { + GridLeanMap map = new GridLeanMap<>(3); + + map.put(k1, v1); + map.put(k2, v2); + map.put(k3, v3); + + return map; + } + + /** * @param col non-null collection with one element * @return a SingletonList containing the element in the original collection */ @@ -9699,7 +9753,7 @@ public abstract class IgniteUtils { public static List arrayList(Collection c, @Nullable IgnitePredicate... p) { assert c != null; - return arrayList(c, c.size(), p); + return arrayList(c.iterator(), c.size(), p); } /** @@ -9718,14 +9772,16 @@ public abstract class IgniteUtils { * @param p Optional filters. * @return Resulting array list. */ - public static List arrayList(Iterable c, int cap, + public static List arrayList(Iterator c, int cap, @Nullable IgnitePredicate... p) { assert c != null; assert cap >= 0; List list = new ArrayList<>(cap); - for (T t : c) { + while (c.hasNext()) { + T t = c.next(); + if (F.isAll(t, p)) list.add(t); } diff --git a/modules/core/src/test/config/log4j-test.xml b/modules/core/src/test/config/log4j-test.xml index bb5f94a..7206b4e 100755 --- a/modules/core/src/test/config/log4j-test.xml +++ b/modules/core/src/test/config/log4j-test.xml @@ -97,6 +97,15 @@ --> + + + diff --git a/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java b/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java index 8d318dc..3e1568a 100644 --- a/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java +++ b/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; +import static org.apache.ignite.configuration.WALMode.LOG_ONLY; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.LOST; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING; import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.DFLT_STORE_DIR; @@ -75,6 +76,8 @@ public class ResetLostPartitionTest extends GridCommonAbstractTest { DataStorageConfiguration storageCfg = new DataStorageConfiguration(); + storageCfg.setPageSize(1024).setWalMode(LOG_ONLY).setWalSegmentSize(8 * 1024 * 1024); + storageCfg.getDefaultDataRegionConfiguration() .setPersistenceEnabled(true) .setMaxSize(500L * 1024 * 1024); @@ -104,7 +107,7 @@ public class ResetLostPartitionTest extends GridCommonAbstractTest { .setBackups(1) .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC) .setPartitionLossPolicy(PartitionLossPolicy.READ_ONLY_SAFE) - .setAffinity(new RendezvousAffinityFunction(false, 1024)) + .setAffinity(new RendezvousAffinityFunction(false, 64)) .setIndexedTypes(String.class, String.class); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java b/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java index 988395f..5969d25 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java @@ -18,10 +18,10 @@ package org.apache.ignite.internal; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -30,7 +30,7 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.managers.communication.GridIoMessage; -import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiInClosure; @@ -300,7 +300,7 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi { * Stops block messages and sends all already blocked messages. */ public void stopBlock() { - stopBlock(true, null); + stopBlock(true, null, true, true); } /** @@ -309,7 +309,7 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi { * @param sndMsgs {@code True} to send blocked messages. */ public void stopBlock(boolean sndMsgs) { - stopBlock(sndMsgs, null); + stopBlock(sndMsgs, null, true, true); } /** @@ -320,15 +320,37 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi { * @param unblockPred If not null unblocks only messages allowed by predicate. */ public void stopBlock(boolean sndMsgs, @Nullable IgnitePredicate> unblockPred) { + stopBlock(sndMsgs, unblockPred, true, true); + } + + /** + * Stops block messages and sends all already blocked messages if sndMsgs is 'true' optionally filtered by + * unblockPred. + * + * @param sndMsgs If {@code true} sends blocked messages. + * @param unblockPred If not null unblocks only messages allowed by predicate. + * @param clearFilters {@code true} to clear filters. + * @param rmvBlockedMsgs {@code true} to remove blocked messages. Sometimes useful in conjunction with {@code + * sndMsgs=false}. + */ + public void stopBlock(boolean sndMsgs, @Nullable IgnitePredicate> unblockPred, + boolean clearFilters, boolean rmvBlockedMsgs) { synchronized (this) { - blockCls.clear(); - blockP = null; + if (clearFilters) { + blockCls.clear(); + blockP = null; + } - Collection> msgs = - unblockPred == null ? blockedMsgs : F.view(blockedMsgs, unblockPred); + Iterator> iter = blockedMsgs.iterator(); - if (sndMsgs) { - for (T2 msg : msgs) { + while (iter.hasNext()) { + T2 msg = iter.next(); + + // It is important what predicate if called only once for each message. + if (unblockPred != null && !unblockPred.apply(msg)) + continue; + + if (sndMsgs) { try { ignite.log().info("Send blocked message [node=" + msg.get1().id() + ", order=" + msg.get1().order() + @@ -340,9 +362,18 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi { U.error(ignite.log(), "Failed to send blocked message: " + msg, e); } } - } - msgs.clear(); + if (rmvBlockedMsgs) + iter.remove(); + } } } + + /** + * Stop blocking all messages. + */ + public static void stopBlockAll() { + for (Ignite ignite : G.allGrids()) + spi(ignite).stopBlock(true); + } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java index 222b161..2f02e10 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java @@ -115,7 +115,8 @@ import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_REA import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; /** - * + * TODO FIXME Mixed atomic-tx cache groups currently are broken if tx cache is dynamically started after atomic. + * TODO FIXME See https://issues.apache.org/jira/browse/IGNITE-11797 */ @SuppressWarnings({"unchecked", "ThrowableNotThrown"}) public class IgniteCacheGroupsTest extends GridCommonAbstractTest { @@ -2291,7 +2292,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { for (final int i : sequence(loaders)) { final IgniteDataStreamer ldr = clientNode.dataStreamer(cache.getName()); - + ldr.allowOverwrite(true); // TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11793 ldr.autoFlushFrequency(0); cls.add(new Callable() { @@ -2985,6 +2986,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { } /** + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 * @throws Exception If failed. */ @Test @@ -3090,6 +3092,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { } /** + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 * @throws Exception If failed. */ @Test @@ -3196,7 +3199,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { IgniteCache cache = node.createCache(cacheConfiguration(grp, "tmpCache-" + cntr++, PARTITIONED, - rnd.nextBoolean() ? ATOMIC : TRANSACTIONAL, + grp.equals(GROUP1) ? ATOMIC : TRANSACTIONAL, backups, rnd.nextBoolean())); @@ -3816,6 +3819,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { } /** + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 * @throws Exception If failed. */ @Test @@ -3824,6 +3828,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { } /** + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 * @throws Exception If failed. */ @Test @@ -3846,8 +3851,8 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { client.createCache(cacheConfiguration(GROUP1, "c2", PARTITIONED, TRANSACTIONAL, 1, false)); client.createCache(cacheConfiguration(GROUP1, "c3", PARTITIONED, ATOMIC, 1, false)); - client.createCache(cacheConfiguration(GROUP2, "c4", PARTITIONED, TRANSACTIONAL, 1, false)); - client.createCache(cacheConfiguration(GROUP2, "c5", PARTITIONED, ATOMIC, 1, false)); + client.createCache(cacheConfiguration(GROUP2, "c4", PARTITIONED, ATOMIC, 1, false)); + client.createCache(cacheConfiguration(GROUP2, "c5", PARTITIONED, TRANSACTIONAL, 1, false)); client.createCache(cacheConfiguration(GROUP2, "c6", PARTITIONED, TRANSACTIONAL, 1, false)); client.createCache(cacheConfiguration(null, "c7", PARTITIONED, ATOMIC, 1, false)); @@ -3946,6 +3951,7 @@ public class IgniteCacheGroupsTest extends GridCommonAbstractTest { } /** + * TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11797 * @throws Exception If failed. */ @Test diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePartitionLossDetectionOnNodeLeftTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePartitionLossDetectionOnNodeLeftTest.java new file mode 100644 index 0000000..61b024c --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePartitionLossDetectionOnNodeLeftTest.java @@ -0,0 +1,115 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.ignite.Ignite; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.events.CacheRebalancingEvent; +import org.apache.ignite.events.EventType; +import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheMode.PARTITIONED; +import static org.apache.ignite.cache.PartitionLossPolicy.IGNORE; +import static org.apache.ignite.testframework.GridTestUtils.mergeExchangeWaitVersion; + +/** + * Tests if lost partitions are same on left nodes after other owners removal. + */ +@RunWith(JUnit4.class) +public class CachePartitionLossDetectionOnNodeLeftTest extends GridCommonAbstractTest { + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setConsistentId(igniteInstanceName); + + cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME). + setAtomicityMode(TRANSACTIONAL). + setCacheMode(PARTITIONED). + setPartitionLossPolicy(IGNORE). // If default will ever change... + setBackups(0)); + + return cfg; + } + + /** + * + */ + @Test + public void testPartitionLossDetectionOnNodeLeft() throws Exception { + try { + final Ignite srv0 = startGrids(5); + + List lost0 = Collections.synchronizedList(new ArrayList<>()); + List lost1 = Collections.synchronizedList(new ArrayList<>()); + + grid(0).events().localListen(evt -> { + lost0.add(((CacheRebalancingEvent)evt).partition()); + + return true; + }, EventType.EVT_CACHE_REBALANCE_PART_DATA_LOST); + + grid(1).events().localListen(evt -> { + lost1.add(((CacheRebalancingEvent)evt).partition()); + + return true; + }, EventType.EVT_CACHE_REBALANCE_PART_DATA_LOST); + + awaitPartitionMapExchange(); + ... 6200 lines suppressed ...