IGNITE-8485: TDE implementation. - Fixes #4167. Signed-off-by: Nikolay Izhikov <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/aabacfa0 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/aabacfa0 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/aabacfa0 Branch: refs/heads/master Commit: aabacfa00f5fd7ef89c9a5bda7b236ff45ed2ac4 Parents: 754c733 Author: Nikolay Izhikov <[email protected]> Authored: Fri Oct 5 12:55:06 2018 +0300 Committer: Nikolay Izhikov <[email protected]> Committed: Fri Oct 5 12:55:06 2018 +0300 ---------------------------------------------------------------------- .../JmhKeystoreEncryptionSpiBenchmark.java | 117 +++ .../ignite/codegen/MessageCodeGenerator.java | 2 + .../configuration/CacheConfiguration.java | 33 + .../configuration/IgniteConfiguration.java | 27 + .../apache/ignite/internal/GridComponent.java | 9 +- .../ignite/internal/GridKernalContext.java | 8 + .../ignite/internal/GridKernalContextImpl.java | 12 + .../org/apache/ignite/internal/GridTopic.java | 5 +- .../apache/ignite/internal/IgniteKernal.java | 2 + .../ignite/internal/IgniteNodeAttributes.java | 3 + .../org/apache/ignite/internal/IgnitionEx.java | 4 + .../communication/GridIoMessageFactory.java | 12 + .../discovery/GridDiscoveryManager.java | 2 + .../GenerateEncryptionKeyRequest.java | 142 +++ .../GenerateEncryptionKeyResponse.java | 148 ++++ .../encryption/GridEncryptionManager.java | 864 +++++++++++++++++++ .../ignite/internal/pagemem/PageMemory.java | 6 + .../pagemem/impl/PageMemoryNoStoreImpl.java | 5 + .../internal/pagemem/store/PageStore.java | 27 + .../pagemem/wal/record/EncryptedRecord.java | 60 ++ .../pagemem/wal/record/PageSnapshot.java | 19 +- .../internal/pagemem/wal/record/WALRecord.java | 8 +- .../delta/DataPageInsertFragmentRecord.java | 2 +- .../wal/record/delta/DataPageInsertRecord.java | 2 +- .../delta/DataPageMvccMarkUpdatedRecord.java | 2 +- .../DataPageMvccUpdateNewTxStateHintRecord.java | 2 +- .../DataPageMvccUpdateTxStateHintRecord.java | 2 +- .../wal/record/delta/DataPageRemoveRecord.java | 2 +- .../wal/record/delta/DataPageUpdateRecord.java | 2 +- .../wal/record/delta/InitNewPageRecord.java | 2 +- .../wal/record/delta/MetaPageAddRootRecord.java | 2 +- .../wal/record/delta/MetaPageCutRootRecord.java | 2 +- .../wal/record/delta/MetaPageInitRecord.java | 2 +- .../delta/MetaPageInitRootInlineRecord.java | 2 +- .../record/delta/MetaPageInitRootRecord.java | 2 +- .../wal/record/delta/NewRootInitRecord.java | 3 +- .../record/delta/PagesListAddPageRecord.java | 2 +- .../delta/PagesListInitNewPageRecord.java | 4 +- .../record/delta/TrackingPageDeltaRecord.java | 2 +- .../IgniteAuthenticationProcessor.java | 16 +- .../processors/cache/ClusterCachesInfo.java | 34 +- .../cache/DynamicCacheChangeRequest.java | 17 + .../processors/cache/GridCacheAttributes.java | 9 +- .../processors/cache/GridCacheProcessor.java | 135 ++- .../processors/cache/GridCacheUtils.java | 23 + .../cache/IgniteCacheOffheapManagerImpl.java | 10 +- .../GridDhtPartitionsExchangeFuture.java | 2 + .../processors/cache/mvcc/MvccUtils.java | 3 +- .../cache/persistence/CacheDataRowAdapter.java | 2 +- .../cache/persistence/DataStructure.java | 6 +- .../GridCacheDatabaseSharedManager.java | 3 + .../persistence/GridCacheOffheapManager.java | 23 +- .../cache/persistence/file/EncryptedFileIO.java | 371 ++++++++ .../file/EncryptedFileIOFactory.java | 100 +++ .../cache/persistence/file/FilePageStore.java | 28 +- .../persistence/file/FilePageStoreFactory.java | 3 +- .../persistence/file/FilePageStoreManager.java | 76 +- .../file/FileVersionCheckingFactory.java | 25 +- .../cache/persistence/freelist/PagesList.java | 4 +- .../persistence/metastorage/MetaStorage.java | 2 + .../persistence/pagemem/PageMemoryImpl.java | 30 +- .../cache/persistence/tree/io/BPlusIO.java | 4 +- .../cache/persistence/tree/io/PageIO.java | 5 +- .../tree/io/PagePartitionCountersIO.java | 2 +- .../persistence/tree/util/PageHandler.java | 50 +- .../wal/reader/StandaloneGridKernalContext.java | 6 + .../reader/StandaloneWalRecordsIterator.java | 3 + .../wal/serializer/RecordDataV1Serializer.java | 355 +++++++- .../wal/serializer/RecordDataV2Serializer.java | 60 +- .../serializer/RecordSerializerFactoryImpl.java | 5 +- .../wal/serializer/RecordV1Serializer.java | 8 +- .../wal/serializer/RecordV2Serializer.java | 2 +- .../cluster/ChangeGlobalStateMessage.java | 6 +- .../cluster/GridClusterStateProcessor.java | 2 + .../utils/PlatformConfigurationUtils.java | 59 ++ .../processors/query/GridQueryProcessor.java | 6 +- .../ignite/internal/util/IgniteUtils.java | 65 ++ .../ignite/internal/util/lang/GridFunc.java | 6 +- .../ignite/spi/encryption/EncryptionSpi.java | 113 +++ .../keystore/KeystoreEncryptionKey.java | 84 ++ .../keystore/KeystoreEncryptionSpi.java | 501 +++++++++++ .../spi/encryption/keystore/package-info.java | 22 + .../spi/encryption/noop/NoopEncryptionSpi.java | 101 +++ .../ignite/spi/encryption/package-info.java | 22 + .../encryption/AbstractEncryptionTest.java | 245 ++++++ .../encryption/EncryptedCacheBigEntryTest.java | 114 +++ .../encryption/EncryptedCacheCreateTest.java | 164 ++++ .../encryption/EncryptedCacheDestroyTest.java | 127 +++ .../EncryptedCacheGroupCreateTest.java | 116 +++ .../encryption/EncryptedCacheNodeJoinTest.java | 237 +++++ .../EncryptedCachePreconfiguredRestartTest.java | 87 ++ .../encryption/EncryptedCacheRestartTest.java | 64 ++ .../pagemem/impl/PageMemoryNoLoadSelfTest.java | 18 +- ...gnitePdsRecoveryAfterFileCorruptionTest.java | 8 +- ...ckpointSimulationWithRealCpDisabledTest.java | 21 +- .../db/file/IgnitePdsPageReplacementTest.java | 2 +- .../persistence/db/wal/WalCompactionTest.java | 12 +- .../pagemem/BPlusTreePageMemoryImplTest.java | 22 +- .../BPlusTreeReuseListPageMemoryImplTest.java | 18 +- ...gnitePageMemReplaceDelayedWriteUnitTest.java | 7 +- .../pagemem/IndexStoragePageMemoryImplTest.java | 22 +- .../pagemem/PageMemoryImplNoLoadTest.java | 22 +- .../persistence/pagemem/PageMemoryImplTest.java | 7 + .../wal/memtracker/PageMemoryTracker.java | 13 + .../KeystoreEncryptionSpiSelfTest.java | 123 +++ .../ignite/testframework/GridTestUtils.java | 81 +- .../testframework/junits/GridAbstractTest.java | 4 +- .../IgniteBasicWithPersistenceTestSuite.java | 15 + .../testsuites/IgniteKernalSelfTestSuite.java | 1 - .../ignite/testsuites/IgniteSpiTestSuite.java | 3 + .../src/test/resources/other_tde_keystore.jks | Bin 0 -> 347 bytes modules/core/src/test/resources/tde.jks | Bin 0 -> 347 bytes .../query/h2/ddl/DdlStatementsProcessor.java | 3 +- .../query/h2/sql/GridSqlCreateTable.java | 17 + .../query/h2/sql/GridSqlQueryParser.java | 8 + .../cache/encryption/EncryptedSqlTableTest.java | 69 ++ .../cache/index/H2DynamicTableSelfTest.java | 4 +- .../IgniteCacheQuerySelfTestSuite.java | 2 + modules/indexing/src/test/resources/tde.jks | Bin 0 -> 347 bytes .../Apache.Ignite.Core.Tests.DotNetCore/tde.jks | Bin 0 -> 347 bytes .../ApiParity/IgniteConfigurationParityTest.cs | 5 +- .../IgniteConfigurationTest.cs | 17 + .../Apache.Ignite.Core.csproj | 6 +- .../Cache/Configuration/CacheConfiguration.cs | 13 + .../Encryption/IEncryptionSpi.cs | 34 + .../Keystore/KeystoreEncryptionSpi.cs | 84 ++ .../Encryption/Keystore/Package-Info.cs | 26 + .../Encryption/Package-Info.cs | 26 + .../Apache.Ignite.Core/IgniteConfiguration.cs | 31 + .../IgniteConfigurationSection.xsd | 39 +- .../spring/src/test/config/enc/base-enc-cfg.xml | 70 ++ .../src/test/config/enc/enc-cache-client.xml | 35 + .../spring/src/test/config/enc/enc-cache.xml | 35 + .../spring/src/test/config/enc/enc-group-2.xml | 36 + .../spring/src/test/config/enc/enc-group.xml | 37 + .../config/enc/not-encrypted-cache-in-group.xml | 36 + .../src/test/config/enc/not-encrypted-cache.xml | 35 + .../SpringEncryptedCacheRestartClientTest.java | 60 ++ .../SpringEncryptedCacheRestartTest.java | 190 ++++ .../testsuites/IgniteSpringTestSuite.java | 6 + modules/spring/src/test/resources/tde.jks | Bin 0 -> 347 bytes .../config/benchmark-multicast-tde.properties | 128 +++ modules/yardstick/config/ignite-base-config.xml | 18 +- modules/yardstick/config/ignite-tde-config.xml | 55 ++ modules/yardstick/src/main/resources/tde.jks | Bin 0 -> 347 bytes 145 files changed, 6319 insertions(+), 320 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java ---------------------------------------------------------------------- diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java new file mode 100644 index 0000000..932d57e --- /dev/null +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.benchmarks.jmh.encryption; + +import java.nio.ByteBuffer; +import java.util.concurrent.ThreadLocalRandom; +import org.apache.ignite.internal.benchmarks.jmh.JmhAbstractBenchmark; +import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey; +import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath; + +/** + */ +public class JmhKeystoreEncryptionSpiBenchmark extends JmhAbstractBenchmark { + /** Data amount. */ + private static final int DATA_AMOUNT = 100; + + public static final int PAGE_SIZE = 1024 * 4; + + /** */ + @Benchmark + public void encryptBenchmark(EncryptionData d, Blackhole receiver) { + for (int i = 0; i < DATA_AMOUNT; i++) { + ByteBuffer[] dt = d.randomData[i]; + + KeystoreEncryptionKey key = d.keys[ThreadLocalRandom.current().nextInt(4)]; + + d.encSpi.encryptNoPadding(dt[0], key, dt[1]); + + receiver.consume(d.res); + + dt[0].rewind(); + dt[1].rewind(); + + d.encSpi.decryptNoPadding(dt[1], key, dt[0]); + } + } + + @State(Scope.Thread) + public static class EncryptionData { + KeystoreEncryptionSpi encSpi; + + KeystoreEncryptionKey[] keys = new KeystoreEncryptionKey[4]; + + ByteBuffer[][] randomData = new ByteBuffer[DATA_AMOUNT][2]; + + ByteBuffer res = ByteBuffer.allocate(PAGE_SIZE); + + public EncryptionData() { + encSpi = new KeystoreEncryptionSpi(); + + encSpi.setKeyStorePath(resolveIgnitePath("modules/core/src/test/resources/tde.jks").getAbsolutePath()); + encSpi.setKeyStorePassword("love_sex_god".toCharArray()); + + encSpi.onBeforeStart(); + encSpi.spiStart("test-instance"); + } + + @Setup(Level.Invocation) + public void prepareCollection() { + for (int i = 0; i < keys.length; i++) + keys[i] = encSpi.create(); + + for (int i = 0; i < DATA_AMOUNT; i++) { + byte[] dt = new byte[PAGE_SIZE - 16]; + + ThreadLocalRandom.current().nextBytes(dt); + + randomData[i][0] = ByteBuffer.wrap(dt); + randomData[i][1] = ByteBuffer.allocate(PAGE_SIZE); + } + } + + @TearDown(Level.Iteration) + public void tearDown() { + //No - op + } + } + + public static void main(String[] args) throws Exception { + Options opt = new OptionsBuilder() + .include(JmhKeystoreEncryptionSpiBenchmark.class.getSimpleName()) + .threads(1) + .forks(1) + .warmupIterations(10) + .measurementIterations(20) + .build(); + + new Runner(opt).run(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java ---------------------------------------------------------------------- diff --git a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java index 2f7e6c0..2599d7a 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java +++ b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java @@ -240,6 +240,8 @@ public class MessageCodeGenerator { // gen.generateAndWrite(GridH2DmlResponse.class); // gen.generateAndWrite(GridNearTxEnlistRequest.class); // gen.generateAndWrite(GridNearTxEnlistResponse.class); +// gen.generateAndWrite(GenerateEncryptionKeyRequest.class); +// gen.generateAndWrite(GenerateEncryptionKeyResponse.class); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java index fb3789d..795fcfd 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java @@ -50,7 +50,9 @@ import org.apache.ignite.cache.query.annotations.QuerySqlFunction; import org.apache.ignite.cache.store.CacheStore; import org.apache.ignite.cache.store.CacheStoreSessionListener; import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.spi.encryption.EncryptionSpi; import org.apache.ignite.internal.binary.BinaryContext; +import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi; import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.A; @@ -373,6 +375,15 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { /** Events disabled. */ private boolean evtsDisabled = DFLT_EVENTS_DISABLED; + /** + * Flag indicating whether data must be encrypted. + * If {@code true} data on the disk will be encrypted. + * + * @see EncryptionSpi + * @see KeystoreEncryptionSpi + */ + private boolean encryptionEnabled; + /** Empty constructor (all values are initialized to their defaults). */ public CacheConfiguration() { /* No-op. */ @@ -412,6 +423,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { cpOnRead = cc.isCopyOnRead(); dfltLockTimeout = cc.getDefaultLockTimeout(); eagerTtl = cc.isEagerTtl(); + encryptionEnabled = cc.isEncryptionEnabled(); evictFilter = cc.getEvictionFilter(); evictPlc = cc.getEvictionPolicy(); evictPlcFactory = cc.getEvictionPolicyFactory(); @@ -2268,6 +2280,27 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { return this; } + /** + * Gets flag indicating whether data must be encrypted. + * + * @return {@code True} if this cache persistent data is encrypted. + */ + public boolean isEncryptionEnabled() { + return encryptionEnabled; + } + + /** + * Sets encrypted flag. + * + * @param encryptionEnabled {@code True} if this cache persistent data should be encrypted. + * @return {@code this} for chaining. + */ + public CacheConfiguration<K, V> setEncryptionEnabled(boolean encryptionEnabled) { + this.encryptionEnabled = encryptionEnabled; + + return this; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheConfiguration.class, this); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java index 964c73b..1dbec7d 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java @@ -40,6 +40,7 @@ import org.apache.ignite.cluster.ClusterGroup; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.compute.ComputeJob; import org.apache.ignite.compute.ComputeTask; +import org.apache.ignite.spi.encryption.EncryptionSpi; import org.apache.ignite.events.Event; import org.apache.ignite.events.EventType; import org.apache.ignite.failure.FailureHandler; @@ -367,6 +368,9 @@ public class IgniteConfiguration { /** Address resolver. */ private AddressResolver addrRslvr; + /** Encryption SPI. */ + private EncryptionSpi encryptionSpi; + /** Cache configurations. */ private CacheConfiguration[] cacheCfg; @@ -537,6 +541,7 @@ public class IgniteConfiguration { failSpi = cfg.getFailoverSpi(); loadBalancingSpi = cfg.getLoadBalancingSpi(); indexingSpi = cfg.getIndexingSpi(); + encryptionSpi = cfg.getEncryptionSpi(); commFailureRslvr = cfg.getCommunicationFailureResolver(); @@ -2062,6 +2067,28 @@ public class IgniteConfiguration { } /** + * Sets fully configured instances of {@link EncryptionSpi}. + * + * @param encryptionSpi Fully configured instance of {@link EncryptionSpi}. + * @see IgniteConfiguration#getEncryptionSpi() + * @return {@code this} for chaining. + */ + public IgniteConfiguration setEncryptionSpi(EncryptionSpi encryptionSpi) { + this.encryptionSpi = encryptionSpi; + + return this; + } + + /** + * Gets fully configured encryption SPI implementations. + * + * @return Encryption SPI implementation. + */ + public EncryptionSpi getEncryptionSpi() { + return encryptionSpi; + } + + /** * Gets address resolver for addresses mapping determination. * * @return Address resolver. http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java index 0cf3a6e..607217e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java @@ -67,7 +67,10 @@ public interface GridComponent { AUTH_PROC, /** */ - CACHE_CRD_PROC + CACHE_CRD_PROC, + + /** Encryption manager. */ + ENCRYPTION_MGR } /** @@ -153,7 +156,7 @@ public interface GridComponent { @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node); /** */ - @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node, DiscoveryDataBag.JoiningNodeDiscoveryData discoData); + @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node, JoiningNodeDiscoveryData discoData); /** * Gets unique component type to distinguish components providing discovery data. Must return non-null value @@ -180,4 +183,4 @@ public interface GridComponent { * @return Future to wait before completing reconnect future. */ @Nullable public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) throws IgniteCheckedException; -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java index 4cb68da..970b8e7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java @@ -28,6 +28,7 @@ import org.apache.ignite.internal.managers.collision.GridCollisionManager; import org.apache.ignite.internal.managers.communication.GridIoManager; import org.apache.ignite.internal.managers.deployment.GridDeploymentManager; import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager; +import org.apache.ignite.internal.managers.encryption.GridEncryptionManager; import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager; import org.apache.ignite.internal.managers.failover.GridFailoverManager; import org.apache.ignite.internal.managers.indexing.GridIndexingManager; @@ -425,6 +426,13 @@ public interface GridKernalContext extends Iterable<GridComponent> { public GridIndexingManager indexing(); /** + * Gets encryption manager. + * + * @return Encryption manager. + */ + public GridEncryptionManager encryption(); + + /** * Gets workers registry. * * @return Workers registry. http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java index a0e3f93..f23e650 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java @@ -38,6 +38,7 @@ import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.failure.FailureType; +import org.apache.ignite.internal.managers.encryption.GridEncryptionManager; import org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager; import org.apache.ignite.internal.managers.collision.GridCollisionManager; import org.apache.ignite.internal.managers.communication.GridIoManager; @@ -162,6 +163,10 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable @GridToStringExclude private GridIndexingManager indexingMgr; + /** */ + @GridToStringExclude + private GridEncryptionManager encryptionMgr; + /* * Processors. * ========== @@ -557,6 +562,8 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable loadMgr = (GridLoadBalancerManager)comp; else if (comp instanceof GridIndexingManager) indexingMgr = (GridIndexingManager)comp; + else if (comp instanceof GridEncryptionManager) + encryptionMgr = (GridEncryptionManager)comp; /* * Processors. @@ -802,6 +809,11 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable } /** {@inheritDoc} */ + @Override public GridEncryptionManager encryption() { + return encryptionMgr; + } + + /** {@inheritDoc} */ @Override public WorkersRegistry workersRegistry() { return workersRegistry; } http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java index 98a4d8d..95d7717 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java @@ -133,7 +133,10 @@ public enum GridTopic { TOPIC_EXCHANGE, /** */ - TOPIC_CACHE_COORDINATOR; + TOPIC_CACHE_COORDINATOR, + + /** */ + TOPIC_GEN_ENC_KEY; /** Enum values. */ private static final GridTopic[] VALS = values(); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 32e5dd8..cfde78f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -101,6 +101,7 @@ import org.apache.ignite.internal.binary.BinaryMarshaller; import org.apache.ignite.internal.binary.BinaryUtils; import org.apache.ignite.internal.cluster.ClusterGroupAdapter; import org.apache.ignite.internal.cluster.IgniteClusterEx; +import org.apache.ignite.internal.managers.encryption.GridEncryptionManager; import org.apache.ignite.internal.managers.GridManager; import org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager; import org.apache.ignite.internal.managers.collision.GridCollisionManager; @@ -987,6 +988,7 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable { startManager(new GridFailoverManager(ctx)); startManager(new GridCollisionManager(ctx)); startManager(new GridIndexingManager(ctx)); + startManager(new GridEncryptionManager(ctx)); ackSecurity(); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java index 5b764e4..4ca4f1b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java @@ -196,6 +196,9 @@ public final class IgniteNodeAttributes { /** User authentication enabled flag. */ public static final String ATTR_AUTHENTICATION_ENABLED = ATTR_PREFIX + ".authentication.enabled"; + /** Encryption master key digest. */ + public static final String ATTR_ENCRYPTION_MASTER_KEY_DIGEST = ATTR_PREFIX + ".master.key.digest"; + /** Rebalance thread pool size. */ public static final String ATTR_REBALANCE_POOL_SIZE = ATTR_PREFIX + ".rebalance.pool.size"; http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java index ed0fbe9..95001de 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java @@ -115,6 +115,7 @@ import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder; +import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi; import org.apache.ignite.spi.eventstorage.NoopEventStorageSpi; import org.apache.ignite.spi.failover.always.AlwaysFailoverSpi; import org.apache.ignite.spi.indexing.noop.NoopIndexingSpi; @@ -2444,6 +2445,9 @@ public class IgnitionEx { if (cfg.getIndexingSpi() == null) cfg.setIndexingSpi(new NoopIndexingSpi()); + + if (cfg.getEncryptionSpi() == null) + cfg.setEncryptionSpi(new NoopEncryptionSpi()); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java index 54efb47..e405d7d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java @@ -46,6 +46,8 @@ import org.apache.ignite.internal.processors.cache.CacheEvictionEntry; import org.apache.ignite.internal.processors.cache.CacheInvokeDirectResult; import org.apache.ignite.internal.processors.cache.CacheObjectByteArrayImpl; import org.apache.ignite.internal.processors.cache.CacheObjectImpl; +import org.apache.ignite.internal.managers.encryption.GenerateEncryptionKeyRequest; +import org.apache.ignite.internal.managers.encryption.GenerateEncryptionKeyResponse; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheReturn; @@ -1084,6 +1086,16 @@ public class GridIoMessageFactory implements MessageFactory { break; + case 162: + msg = new GenerateEncryptionKeyRequest(); + + break; + + case 163: + msg = new GenerateEncryptionKeyResponse(); + + break; + // [-3..119] [124..129] [-23..-27] [-36..-55]- this // [120..123] - DR // [-4..-22, -30..-35] - SQL http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java index 19c11ac..d7514a0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java @@ -795,6 +795,8 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> { ctx.cache().context().exchange().onLocalJoin(discoEvt, discoCache); ctx.authentication().onLocalJoin(); + + ctx.encryption().onLocalJoin(); } IgniteInternalFuture<Boolean> transitionWaitFut = ctx.state().onLocalJoin(discoCache); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java new file mode 100644 index 0000000..3d48014 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java @@ -0,0 +1,142 @@ +/* + * 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.managers.encryption; + +import java.nio.ByteBuffer; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * Generate encryption key request. + */ +public class GenerateEncryptionKeyRequest implements Message { + /** */ + private static final long serialVersionUID = 0L; + + /** Request ID. */ + private IgniteUuid id = IgniteUuid.randomUuid(); + + /** */ + private int keyCnt; + + /** */ + public GenerateEncryptionKeyRequest() { + } + + /** + * @param keyCnt Count of encryption key to generate. + */ + public GenerateEncryptionKeyRequest(int keyCnt) { + this.keyCnt = keyCnt; + } + + /** + * @return Request id. + */ + public IgniteUuid id() { + return id; + } + + /** + * @return Count of encryption key to generate. + */ + public int keyCount() { + return keyCnt; + } + + /** {@inheritDoc} */ + @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { + writer.setBuffer(buf); + + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(directType(), fieldsCount())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeIgniteUuid("id", id)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeInt("keyCnt", keyCnt)) + return false; + + writer.incrementState(); + + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { + reader.setBuffer(buf); + + if (!reader.beforeMessageRead()) + return false; + + switch (reader.state()) { + case 0: + id = reader.readIgniteUuid("id"); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + keyCnt = reader.readInt("keyCnt"); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + } + + return reader.afterMessageRead(GenerateEncryptionKeyRequest.class); + } + + /** {@inheritDoc} */ + @Override public short directType() { + return 162; + } + + /** {@inheritDoc} */ + @Override public byte fieldsCount() { + return 2; + } + + /** {@inheritDoc} */ + @Override public void onAckReceived() { + // No-op. + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(GenerateEncryptionKeyRequest.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java new file mode 100644 index 0000000..8971248 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java @@ -0,0 +1,148 @@ +/* + * 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.managers.encryption; + +import java.nio.ByteBuffer; +import java.util.Collection; +import org.apache.ignite.internal.GridDirectCollection; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * Generate encryption key response. + */ +public class GenerateEncryptionKeyResponse implements Message { + /** */ + private static final long serialVersionUID = 0L; + + /** Request message ID. */ + private IgniteUuid id; + + /** */ + @GridDirectCollection(byte[].class) + private Collection<byte[]> encKeys; + + /** */ + public GenerateEncryptionKeyResponse() { + } + + /** + * @param id Request id. + * @param encKeys Encryption keys. + */ + public GenerateEncryptionKeyResponse(IgniteUuid id, Collection<byte[]> encKeys) { + this.id = id; + this.encKeys = encKeys; + } + + /** + * @return Request id. + */ + public IgniteUuid requestId() { + return id; + } + + /** + * @return Encryption keys. + */ + public Collection<byte[]> encryptionKeys() { + return encKeys; + } + + /** {@inheritDoc} */ + @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { + writer.setBuffer(buf); + + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(directType(), fieldsCount())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeCollection("encKeys", encKeys, MessageCollectionItemType.BYTE_ARR)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeIgniteUuid("id", id)) + return false; + + writer.incrementState(); + + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { + reader.setBuffer(buf); + + if (!reader.beforeMessageRead()) + return false; + + switch (reader.state()) { + case 0: + encKeys = reader.readCollection("encKeys", MessageCollectionItemType.BYTE_ARR); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + id = reader.readIgniteUuid("id"); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + } + + return reader.afterMessageRead(GenerateEncryptionKeyResponse.class); + } + + /** {@inheritDoc} */ + @Override public short directType() { + return 163; + } + + /** {@inheritDoc} */ + @Override public byte fieldsCount() { + return 2; + } + + /** {@inheritDoc} */ + @Override public void onAckReceived() { + //No-op. + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(GenerateEncryptionKeyResponse.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java new file mode 100644 index 0000000..a1c0fdc --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java @@ -0,0 +1,864 @@ +/* + * 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.managers.encryption; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.spi.encryption.EncryptionSpi; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.managers.GridManagerAdapter; +import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.eventstorage.DiscoveryEventListener; +import org.apache.ignite.internal.processors.cache.CacheGroupDescriptor; +import org.apache.ignite.internal.processors.cache.GridCacheProcessor; +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.metastorage.ReadWriteMetastorage; +import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport; +import org.apache.ignite.internal.util.future.GridFinishedFuture; +import org.apache.ignite.internal.util.future.GridFutureAdapter; +import org.apache.ignite.internal.util.lang.GridPlainClosure; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteFuture; +import org.apache.ignite.lang.IgniteFutureCancelledException; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.lang.IgniteProductVersion; +import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.spi.IgniteNodeValidationResult; +import org.apache.ignite.spi.discovery.DiscoveryDataBag; +import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData; +import org.apache.ignite.spi.discovery.DiscoveryDataBag.JoiningNodeDiscoveryData; +import org.apache.ignite.spi.discovery.DiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; +import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; +import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.ENCRYPTION_MGR; +import static org.apache.ignite.internal.GridTopic.TOPIC_GEN_ENC_KEY; +import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_ENCRYPTION_MASTER_KEY_DIGEST; +import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SYSTEM_POOL; + +/** + * Manages cache keys and {@code EncryptionSpi} instances. + * + * NOTE: Following protocol applied to statically configured caches. + * For dynamically created caches key generated in request creation. + * + * Group keys generation protocol: + * + * <ul> + * <li>Joining node: + * <ul> + * <li>1. Collects and send all stored group keys to coordinator.</li> + * <li>2. Generate(but doesn't store locally!) and send keys for all statically configured groups in case the not presented in metastore.</li> + * <li>3. Store all keys received from coordinator to local store.</li> + * </ul> + * </li> + * <li>Coordinator: + * <ul> + * <li>1. Checks master key digest are equal to local. If not join is rejected.</li> + * <li>2. Checks all stored keys from joining node are equal to stored keys. If not join is rejected.</li> + * <li>3. Collects all stored keys and sends it to joining node.</li> + * </ul> + * </li> + * <li>All nodes: + * <ul> + * <li>1. If new key for group doesn't exists locally it added to local store.</li> + * <li>2. If new key for group exists locally, then received key skipped.</li> + * </ul> + * </li> + * </ul> + * + * @see GridCacheProcessor#generateEncryptionKeysAndStartCacheAfter(int, GridPlainClosure) + */ +public class GridEncryptionManager extends GridManagerAdapter<EncryptionSpi> implements MetastorageLifecycleListener, + IgniteChangeGlobalStateSupport { + /** + * Cache encryption introduced in this Ignite version. + */ + private static final IgniteProductVersion CACHE_ENCRYPTION_SINCE = IgniteProductVersion.fromString("2.7.0"); + + /** Synchronization mutex. */ + private final Object metaStorageMux = new Object(); + + /** Synchronization mutex for an generate encryption keys operations. */ + private final Object genEcnKeyMux = new Object(); + + /** Disconnected flag. */ + private volatile boolean disconnected; + + /** Stopped flag. */ + private volatile boolean stopped; + + /** Flag to enable/disable write to metastore on cluster state change. */ + private volatile boolean writeToMetaStoreEnabled; + + /** Prefix for a encryption group key in meta store. */ + public static final String ENCRYPTION_KEY_PREFIX = "grp-encryption-key-"; + + /** Encryption key predicate for meta store. */ + private static final IgnitePredicate<String> ENCRYPTION_KEY_PREFIX_PRED = + (IgnitePredicate<String>)key -> key.startsWith(ENCRYPTION_KEY_PREFIX); + + /** Group encryption keys. */ + private Map<Integer, Serializable> grpEncKeys = new HashMap<>(); + + /** Pending generate encryption key futures. */ + private ConcurrentMap<IgniteUuid, GenerateEncryptionKeyFuture> genEncKeyFuts = new ConcurrentHashMap<>(); + + /** Metastorage. */ + private volatile ReadWriteMetastorage metaStorage; + + /** I/O message listener. */ + private GridMessageListener ioLsnr; + + /** System discovery message listener. */ + private DiscoveryEventListener discoLsnr; + + /** + * @param ctx Kernel context. + */ + public GridEncryptionManager(GridKernalContext ctx) { + super(ctx, ctx.config().getEncryptionSpi()); + + ctx.internalSubscriptionProcessor().registerMetastorageListener(this); + } + + /** {@inheritDoc} */ + @Override public void start() throws IgniteCheckedException { + startSpi(); + + if (getSpi().masterKeyDigest() != null) + ctx.addNodeAttribute(ATTR_ENCRYPTION_MASTER_KEY_DIGEST, getSpi().masterKeyDigest()); + + ctx.event().addDiscoveryEventListener(discoLsnr = (evt, discoCache) -> { + UUID leftNodeId = evt.eventNode().id(); + + synchronized (genEcnKeyMux) { + Iterator<Map.Entry<IgniteUuid, GenerateEncryptionKeyFuture>> futsIter = + genEncKeyFuts.entrySet().iterator(); + + while (futsIter.hasNext()) { + GenerateEncryptionKeyFuture fut = futsIter.next().getValue(); + + if (!F.eq(leftNodeId, fut.nodeId())) + return; + + try { + futsIter.remove(); + + sendGenerateEncryptionKeyRequest(fut); + + genEncKeyFuts.put(fut.id(), fut); + } + catch (IgniteCheckedException e) { + fut.onDone(null, e); + } + } + } + }, EVT_NODE_LEFT, EVT_NODE_FAILED); + + ctx.io().addMessageListener(TOPIC_GEN_ENC_KEY, ioLsnr = (nodeId, msg, plc) -> { + synchronized (genEcnKeyMux) { + if (msg instanceof GenerateEncryptionKeyRequest) { + GenerateEncryptionKeyRequest req = (GenerateEncryptionKeyRequest)msg; + + assert req.keyCount() != 0; + + List<byte[]> encKeys = new ArrayList<>(req.keyCount()); + + for (int i = 0; i < req.keyCount(); i++) + encKeys.add(getSpi().encryptKey(getSpi().create())); + + try { + ctx.io().sendToGridTopic(nodeId, TOPIC_GEN_ENC_KEY, + new GenerateEncryptionKeyResponse(req.id(), encKeys), SYSTEM_POOL); + } + catch (IgniteCheckedException e) { + U.error(log, "Unable to send generate key response[nodeId=" + nodeId + "]"); + } + } + else { + GenerateEncryptionKeyResponse resp = (GenerateEncryptionKeyResponse)msg; + + GenerateEncryptionKeyFuture fut = genEncKeyFuts.get(resp.requestId()); + + if (fut != null) + fut.onDone(resp.encryptionKeys(), null); + else + U.warn(log, "Response received for a unknown request.[reqId=" + resp.requestId() + "]"); + } + } + }); + } + + /** {@inheritDoc} */ + @Override public void stop(boolean cancel) throws IgniteCheckedException { + stopSpi(); + } + + /** {@inheritDoc} */ + @Override protected void onKernalStart0() throws IgniteCheckedException { + // No-op. + } + + /** {@inheritDoc} */ + @Override protected void onKernalStop0(boolean cancel) { + synchronized (genEcnKeyMux) { + stopped = true; + + if (ioLsnr != null) + ctx.io().removeMessageListener(TOPIC_GEN_ENC_KEY, ioLsnr); + + if (discoLsnr != null) + ctx.event().removeDiscoveryEventListener(discoLsnr, EVT_NODE_LEFT, EVT_NODE_FAILED); + + cancelFutures("Kernal stopped."); + } + } + + /** {@inheritDoc} */ + @Override public void onDisconnected(IgniteFuture<?> reconnectFut) { + synchronized (genEcnKeyMux) { + assert !disconnected; + + disconnected = true; + + cancelFutures("Client node was disconnected from topology (operation result is unknown)."); + } + } + + /** {@inheritDoc} */ + @Override public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) { + synchronized (genEcnKeyMux) { + assert disconnected; + + disconnected = false; + + return null; + } + } + + /** + * Callback for local join. + */ + public void onLocalJoin() { + if (notCoordinator()) + return; + + //We can't store keys before node join to cluster(on statically configured cache registration). + //Because, keys should be received from cluster. + //Otherwise, we would generate different keys on each started node. + //So, after starting, coordinator saves locally newly generated encryption keys. + //And sends that keys to every joining node. + synchronized (metaStorageMux) { + //Keys read from meta storage. + HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys(); + + //Generated(not saved!) keys for a new caches. + //Configured statically in config, but doesn't stored on the disk. + HashMap<Integer, byte[]> newEncKeys = + newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet()); + + if (newEncKeys == null) + return; + + //We can store keys to the disk, because we are on a coordinator. + for (Map.Entry<Integer, byte[]> entry : newEncKeys.entrySet()) { + groupKey(entry.getKey(), entry.getValue()); + + U.quietAndInfo(log, "Added encryption key on local join [grpId=" + entry.getKey() + "]"); + } + } + } + + /** {@inheritDoc} */ + @Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode node, + JoiningNodeDiscoveryData discoData) { + IgniteNodeValidationResult res = super.validateNode(node, discoData); + + if (res != null) + return res; + + if (node.isClient()) + return null; + + res = validateNode(node); + + if (res != null) + return res; + + if (!discoData.hasJoiningNodeData()) { + U.quietAndInfo(log, "Joining node doesn't have encryption data [node=" + node.id() + "]"); + + return null; + } + + NodeEncryptionKeys nodeEncKeys = (NodeEncryptionKeys)discoData.joiningNodeData(); + + if (nodeEncKeys == null || F.isEmpty(nodeEncKeys.knownKeys)) { + U.quietAndInfo(log, "Joining node doesn't have stored group keys [node=" + node.id() + "]"); + + return null; + } + + for (Map.Entry<Integer, byte[]> entry : nodeEncKeys.knownKeys.entrySet()) { + Serializable locEncKey = grpEncKeys.get(entry.getKey()); + + if (locEncKey == null) + continue; + + Serializable rmtKey = getSpi().decryptKey(entry.getValue()); + + if (F.eq(locEncKey, rmtKey)) + continue; + + return new IgniteNodeValidationResult(ctx.localNodeId(), + "Cache key differs! Node join is rejected. [node=" + node.id() + ", grp=" + entry.getKey() + "]", + "Cache key differs! Node join is rejected."); + } + + return null; + } + + /** {@inheritDoc} */ + @Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode node) { + IgniteNodeValidationResult res = super.validateNode(node); + + if (res != null) + return res; + + if (node.isClient()) + return null; + + byte[] lclMkDig = getSpi().masterKeyDigest(); + + byte[] rmtMkDig = node.attribute(ATTR_ENCRYPTION_MASTER_KEY_DIGEST); + + if (Arrays.equals(lclMkDig, rmtMkDig)) + return null; + + return new IgniteNodeValidationResult(ctx.localNodeId(), + "Master key digest differs! Node join is rejected. [node=" + node.id() + "]", + "Master key digest differs! Node join is rejected."); + } + + /** {@inheritDoc} */ + @Override public void collectJoiningNodeData(DiscoveryDataBag dataBag) { + HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys(); + + HashMap<Integer, byte[]> newKeys = + newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet()); + + if ((knownEncKeys == null && newKeys == null) || dataBag.isJoiningNodeClient()) + return; + + if (log.isInfoEnabled()) { + String knownGrps = F.isEmpty(knownEncKeys) ? null : F.concat(knownEncKeys.keySet(), ","); + + if (knownGrps != null) + U.quietAndInfo(log, "Sending stored group keys to coordinator [grps=" + knownGrps + "]"); + + String newGrps = F.isEmpty(newKeys) ? null : F.concat(newKeys.keySet(), ","); + + if (newGrps != null) + U.quietAndInfo(log, "Sending new group keys to coordinator [grps=" + newGrps + "]"); + } + + dataBag.addJoiningNodeData(ENCRYPTION_MGR.ordinal(), new NodeEncryptionKeys(knownEncKeys, newKeys)); + } + + /** {@inheritDoc} */ + @Override public void onJoiningNodeDataReceived(JoiningNodeDiscoveryData data) { + NodeEncryptionKeys nodeEncryptionKeys = (NodeEncryptionKeys)data.joiningNodeData(); + + if (nodeEncryptionKeys == null || nodeEncryptionKeys.newKeys == null || ctx.clientNode()) + return; + + for (Map.Entry<Integer, byte[]> entry : nodeEncryptionKeys.newKeys.entrySet()) { + if (groupKey(entry.getKey()) == null) { + U.quietAndInfo(log, "Store group key received from joining node [node=" + + data.joiningNodeId() + ", grp=" + entry.getKey() + "]"); + + groupKey(entry.getKey(), entry.getValue()); + } + else { + U.quietAndInfo(log, "Skip group key received from joining node. Already exists. [node=" + + data.joiningNodeId() + ", grp=" + entry.getKey() + "]"); + } + } + } + + /** {@inheritDoc} */ + @Override public void collectGridNodeData(DiscoveryDataBag dataBag) { + if (dataBag.isJoiningNodeClient() || dataBag.commonDataCollectedFor(ENCRYPTION_MGR.ordinal())) + return; + + HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys(); + + HashMap<Integer, byte[]> newKeys = + newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet()); + + if (knownEncKeys == null) + knownEncKeys = newKeys; + else if (newKeys != null) { + for (Map.Entry<Integer, byte[]> entry : newKeys.entrySet()) { + byte[] old = knownEncKeys.putIfAbsent(entry.getKey(), entry.getValue()); + + assert old == null; + } + } + + dataBag.addGridCommonData(ENCRYPTION_MGR.ordinal(), knownEncKeys); + } + + /** {@inheritDoc} */ + @Override public void onGridDataReceived(GridDiscoveryData data) { + Map<Integer, byte[]> encKeysFromCluster = (Map<Integer, byte[]>)data.commonData(); + + if (F.isEmpty(encKeysFromCluster)) + return; + + for (Map.Entry<Integer, byte[]> entry : encKeysFromCluster.entrySet()) { + if (groupKey(entry.getKey()) == null) { + U.quietAndInfo(log, "Store group key received from coordinator [grp=" + entry.getKey() + "]"); + + groupKey(entry.getKey(), entry.getValue()); + } + else { + U.quietAndInfo(log, "Skip group key received from coordinator. Already exists. [grp=" + + entry.getKey() + "]"); + } + } + } + + /** + * Returns group encryption key. + * + * @param grpId Group id. + * @return Group encryption key. + */ + @Nullable public Serializable groupKey(int grpId) { + return grpEncKeys.get(grpId); + } + + /** + * Store group encryption key. + * + * @param grpId Group id. + * @param encGrpKey Encrypted group key. + */ + public void groupKey(int grpId, byte[] encGrpKey) { + assert !grpEncKeys.containsKey(grpId); + + Serializable encKey = getSpi().decryptKey(encGrpKey); + + synchronized (metaStorageMux) { + if (log.isDebugEnabled()) + log.debug("Key added. [grp=" + grpId + "]"); + + grpEncKeys.put(grpId, encKey); + + writeToMetaStore(grpId, encGrpKey); + } + } + + /** + * Removes encryption key. + * + * @param grpId Group id. + */ + private void removeGroupKey(int grpId) { + synchronized (metaStorageMux) { + ctx.cache().context().database().checkpointReadLock(); + + try { + grpEncKeys.remove(grpId); + + metaStorage.remove(ENCRYPTION_KEY_PREFIX + grpId); + + if (log.isDebugEnabled()) + log.debug("Key removed. [grp=" + grpId + "]"); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to clear meta storage", e); + } + finally { + ctx.cache().context().database().checkpointReadUnlock(); + } + } + } + + /** + * Callback for cache group start event. + * @param grpId Group id. + * @param encKey Encryption key + */ + public void beforeCacheGroupStart(int grpId, @Nullable byte[] encKey) { + if (encKey == null || ctx.clientNode()) + return; + + groupKey(grpId, encKey); + } + + /** + * Callback for cache group destroy event. + * @param grpId Group id. + */ + public void onCacheGroupDestroyed(int grpId) { + if (groupKey(grpId) == null) + return; + + removeGroupKey(grpId); + } + + /** {@inheritDoc} */ + @Override public void onReadyForRead(ReadOnlyMetastorage metastorage) { + try { + Map<String, ? extends Serializable> encKeys = metastorage.readForPredicate(ENCRYPTION_KEY_PREFIX_PRED); + + if (encKeys.isEmpty()) + return; + + for (String key : encKeys.keySet()) { + Integer grpId = Integer.valueOf(key.replace(ENCRYPTION_KEY_PREFIX, "")); + + byte[] encGrpKey = (byte[])encKeys.get(key); + + grpEncKeys.putIfAbsent(grpId, getSpi().decryptKey(encGrpKey)); + } + + if (!grpEncKeys.isEmpty()) { + U.quietAndInfo(log, "Encryption keys loaded from metastore. [grps=" + + F.concat(grpEncKeys.keySet(), ",") + "]"); + } + } + catch (IgniteCheckedException e) { + throw new IgniteException("Failed to read encryption keys state.", e); + } + } + + /** {@inheritDoc} */ + @Override public void onReadyForReadWrite(ReadWriteMetastorage metaStorage) throws IgniteCheckedException { + synchronized (metaStorageMux) { + this.metaStorage = metaStorage; + + writeToMetaStoreEnabled = true; + + writeAllToMetaStore(); + } + } + + /** {@inheritDoc} */ + @Override public void onActivate(GridKernalContext kctx) throws IgniteCheckedException { + synchronized (metaStorageMux) { + writeToMetaStoreEnabled = metaStorage != null; + + if (writeToMetaStoreEnabled) + writeAllToMetaStore(); + } + } + + /** {@inheritDoc} */ + @Override public void onDeActivate(GridKernalContext kctx) { + synchronized (metaStorageMux) { + writeToMetaStoreEnabled = false; + } + } + + /** + * @param keyCnt Count of keys to generate. + * @return Future that will contain results of generation. + */ + public IgniteInternalFuture<Collection<byte[]>> generateKeys(int keyCnt) { + if (keyCnt == 0 || !ctx.clientNode()) + return new GridFinishedFuture<>(createKeys(keyCnt)); + + synchronized (genEcnKeyMux) { + if (disconnected || stopped) { + return new GridFinishedFuture<>( + new IgniteFutureCancelledException("Node " + (stopped ? "stopped" : "disconnected"))); + } + + try { + GenerateEncryptionKeyFuture genEncKeyFut = new GenerateEncryptionKeyFuture(keyCnt); + + sendGenerateEncryptionKeyRequest(genEncKeyFut); + + genEncKeyFuts.put(genEncKeyFut.id(), genEncKeyFut); + + return genEncKeyFut; + } + catch (IgniteCheckedException e) { + return new GridFinishedFuture<>(e); + } + } + } + + /** */ + private void sendGenerateEncryptionKeyRequest(GenerateEncryptionKeyFuture fut) throws IgniteCheckedException { + ClusterNode rndNode = U.randomServerNode(ctx); + + if (rndNode == null) + throw new IgniteCheckedException("There is no node to send GenerateEncryptionKeyRequest to"); + + GenerateEncryptionKeyRequest req = new GenerateEncryptionKeyRequest(fut.keyCount()); + + fut.id(req.id()); + fut.nodeId(rndNode.id()); + + ctx.io().sendToGridTopic(rndNode.id(), TOPIC_GEN_ENC_KEY, req, SYSTEM_POOL); + } + + /** + * Writes all unsaved grpEncKeys to metaStorage. + * @throws IgniteCheckedException If failed. + */ + private void writeAllToMetaStore() throws IgniteCheckedException { + for (Map.Entry<Integer, Serializable> entry : grpEncKeys.entrySet()) { + if (metaStorage.read(ENCRYPTION_KEY_PREFIX + entry.getKey()) != null) + continue; + + writeToMetaStore(entry.getKey(), getSpi().encryptKey(entry.getValue())); + } + } + + /** + * Checks cache encryption supported by all nodes in cluster. + * + * @throws IgniteCheckedException If check fails. + */ + public void checkEncryptedCacheSupported() throws IgniteCheckedException { + Collection<ClusterNode> nodes = ctx.grid().cluster().nodes(); + + for (ClusterNode node : nodes) { + if (CACHE_ENCRYPTION_SINCE.compareTo(node.version()) > 0) { + throw new IgniteCheckedException("All nodes in cluster should be 2.7.0 or greater " + + "to create encrypted cache! [nodeId=" + node.id() + "]"); + } + } + } + + /** {@inheritDoc} */ + @Override public DiscoveryDataExchangeType discoveryDataType() { + return ENCRYPTION_MGR; + } + + /** + * Writes encryption key to metastore. + * + * @param grpId Group id. + * @param encGrpKey Group encryption key. + */ + private void writeToMetaStore(int grpId, byte[] encGrpKey) { + if (metaStorage == null || !writeToMetaStoreEnabled) + return; + + ctx.cache().context().database().checkpointReadLock(); + + try { + metaStorage.write(ENCRYPTION_KEY_PREFIX + grpId, encGrpKey); + } + catch (IgniteCheckedException e) { + throw new IgniteException("Failed to write cache group encryption key [grpId=" + grpId + ']', e); + } + finally { + ctx.cache().context().database().checkpointReadUnlock(); + } + } + + /** + * @param knownKeys Saved keys set. + * @return New keys for local cache groups. + */ + @Nullable private HashMap<Integer, byte[]> newEncryptionKeys(Set<Integer> knownKeys) { + Map<Integer, CacheGroupDescriptor> grpDescs = ctx.cache().cacheGroupDescriptors(); + + HashMap<Integer, byte[]> newKeys = null; + + for (CacheGroupDescriptor grpDesc : grpDescs.values()) { + if (knownKeys.contains(grpDesc.groupId()) || !grpDesc.config().isEncryptionEnabled()) + continue; + + if (newKeys == null) + newKeys = new HashMap<>(); + + newKeys.put(grpDesc.groupId(), getSpi().encryptKey(getSpi().create())); + } + + return newKeys; + } + + /** + * @return Local encryption keys. + */ + @Nullable private HashMap<Integer, byte[]> knownEncryptionKeys() { + if (F.isEmpty(grpEncKeys)) + return null; + + HashMap<Integer, byte[]> knownKeys = new HashMap<>(); + + for (Map.Entry<Integer, Serializable> entry : grpEncKeys.entrySet()) + knownKeys.put(entry.getKey(), getSpi().encryptKey(entry.getValue())); + + return knownKeys; + } + + /** + * Generates required count of encryption keys. + * + * @param keyCnt Keys count. + * @return Collection with newly generated encryption keys. + */ + private Collection<byte[]> createKeys(int keyCnt) { + if (keyCnt == 0) + return Collections.emptyList(); + + List<byte[]> encKeys = new ArrayList<>(keyCnt); + + for(int i=0; i<keyCnt; i++) + encKeys.add(getSpi().encryptKey(getSpi().create())); + + return encKeys; + } + + /** + * @param msg Error message. + */ + private void cancelFutures(String msg) { + for (GenerateEncryptionKeyFuture fut : genEncKeyFuts.values()) + fut.onDone(new IgniteFutureCancelledException(msg)); + } + + /** + * Checks whether local node is coordinator. Nodes that are leaving or failed + * (but are still in topology) are removed from search. + * + * @return {@code true} if local node is coordinator. + */ + private boolean notCoordinator() { + DiscoverySpi spi = ctx.discovery().getInjectedDiscoverySpi(); + + if (spi instanceof TcpDiscoverySpi) + return !((TcpDiscoverySpi)spi).isLocalNodeCoordinator(); + else { + ClusterNode crd = null; + + for (ClusterNode node : ctx.discovery().aliveServerNodes()) { + if (crd == null || crd.order() > node.order()) + crd = node; + } + + return crd == null || !F.eq(ctx.localNodeId(), crd.id()); + } + } + + /** */ + public static class NodeEncryptionKeys implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + NodeEncryptionKeys(Map<Integer, byte[]> knownKeys, Map<Integer, byte[]> newKeys) { + this.knownKeys = knownKeys; + this.newKeys = newKeys; + } + + /** Known i.e. stored in {@code ReadWriteMetastorage} keys from node. */ + Map<Integer, byte[]> knownKeys; + + /** New keys i.e. keys for a local statically configured caches. */ + Map<Integer, byte[]> newKeys; + } + + /** */ + @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor") + private class GenerateEncryptionKeyFuture extends GridFutureAdapter<Collection<byte[]>> { + /** */ + private IgniteUuid id; + + /** */ + private int keyCnt; + + /** */ + private UUID nodeId; + + /** + * @param keyCnt Count of keys to generate. + */ + private GenerateEncryptionKeyFuture(int keyCnt) { + this.keyCnt = keyCnt; + } + + /** {@inheritDoc} */ + @Override public boolean onDone(@Nullable Collection<byte[]> res, @Nullable Throwable err) { + // Make sure to remove future before completion. + genEncKeyFuts.remove(id, this); + + return super.onDone(res, err); + } + + /** */ + public IgniteUuid id() { + return id; + } + + /** */ + public void id(IgniteUuid id) { + this.id = id; + } + + /** */ + public UUID nodeId() { + return nodeId; + } + + /** */ + public void nodeId(UUID nodeId) { + this.nodeId = nodeId; + } + + /** */ + public int keyCount() { + return keyCnt; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(GenerateEncryptionKeyFuture.class, this); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java index f7391d2..3ef0ec7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java @@ -43,6 +43,12 @@ public interface PageMemory extends PageIdAllocator, PageSupport { public int pageSize(); /** + * @param grpId Group id. + * @return Page size without encryption overhead. + */ + public int realPageSize(int grpId); + + /** * @return Page size with system overhead, in bytes. */ public int systemPageSize(); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java index 02afac8..66d713c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java @@ -341,6 +341,11 @@ public class PageMemoryNoStoreImpl implements PageMemory { return sysPageSize; } + /** {@inheritDoc} */ + @Override public int realPageSize(int grpId) { + return pageSize(); + } + /** * @return Next index. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java index 42d584d..7a7f964 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java @@ -20,6 +20,7 @@ package org.apache.ignite.internal.pagemem.store; import org.apache.ignite.IgniteCheckedException; import java.nio.ByteBuffer; +import org.apache.ignite.internal.processors.cache.persistence.StorageException; /** * Persistent store of pages. @@ -101,4 +102,30 @@ public interface PageStore { * @return Page store version. */ public int version(); + + /** + * @param cleanFile {@code True} to delete file. + * @throws StorageException If failed. + */ + public void stop(boolean cleanFile) throws StorageException; + + /** + * Starts recover process. + */ + public void beginRecover(); + + /** + * Ends recover process. + * + * @throws StorageException If failed. + */ + public void finishRecover() throws StorageException; + + /** + * Truncates and deletes partition file. + * + * @param tag New partition tag. + * @throws StorageException If failed. + */ + public void truncate(int tag) throws StorageException; } http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java new file mode 100644 index 0000000..234292b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java @@ -0,0 +1,60 @@ +/* + * 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; + +/** + * Encrypted record from WAL. + * That types of record returned from a {@code RecordDataSerializer} on offline WAL iteration. + */ +public class EncryptedRecord extends WALRecord implements WalRecordCacheGroupAware { + /** + * Group id. + */ + private int grpId; + + /** + * Type of plain record. + */ + private RecordType plainRecType; + + /** + * @param grpId Group id + * @param plainRecType Plain record type. + */ + public EncryptedRecord(int grpId, RecordType plainRecType) { + this.grpId = grpId; + this.plainRecType = plainRecType; + } + + /** {@inheritDoc} */ + @Override public RecordType type() { + return RecordType.ENCRYPTED_RECORD; + } + + /** {@inheritDoc} */ + @Override public int groupId() { + return grpId; + } + + /** + * @return Type of plain record. + */ + public RecordType plainRecordType() { + return plainRecType; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java index 1aa065e..d3a465d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java @@ -38,21 +38,30 @@ public class PageSnapshot extends WALRecord implements WalRecordCacheGroupAware{ private FullPageId fullPageId; /** + * PageSIze without encryption overhead. + */ + private int realPageSize; + + /** * @param fullId Full page ID. * @param arr Read array. + * @param realPageSize Page size without encryption overhead. */ - public PageSnapshot(FullPageId fullId, byte[] arr) { - fullPageId = fullId; - pageData = arr; + public PageSnapshot(FullPageId fullId, byte[] arr, int realPageSize) { + this.fullPageId = fullId; + this.pageData = arr; + this.realPageSize = realPageSize; } /** * @param fullPageId Full page ID. * @param ptr Pointer to copy from. * @param pageSize Page size. + * @param realPageSize Page size without encryption overhead. */ - public PageSnapshot(FullPageId fullPageId, long ptr, int pageSize) { + public PageSnapshot(FullPageId fullPageId, long ptr, int pageSize, int realPageSize) { this.fullPageId = fullPageId; + this.realPageSize = realPageSize; pageData = new byte[pageSize]; @@ -88,7 +97,7 @@ public class PageSnapshot extends WALRecord implements WalRecordCacheGroupAware{ try { return "PageSnapshot [fullPageId = " + fullPageId() + ", page = [\n" - + PageIO.printPage(addr, pageData.length) + + PageIO.printPage(addr, realPageSize) + "],\nsuper = [" + super.toString() + "]]"; } http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java ---------------------------------------------------------------------- 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 a555aae..667f8d9 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 @@ -193,7 +193,13 @@ public abstract class WALRecord { MVCC_DATA_PAGE_TX_STATE_HINT_UPDATED_RECORD, /** */ - MVCC_DATA_PAGE_NEW_TX_STATE_HINT_UPDATED_RECORD; + MVCC_DATA_PAGE_NEW_TX_STATE_HINT_UPDATED_RECORD, + + /** Encrypted WAL-record. */ + ENCRYPTED_RECORD, + + /** Ecnrypted data record */ + ENCRYPTED_DATA_RECORD; /** */ private static final RecordType[] VALS = RecordType.values(); http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java index 2b02bb57..650ae1e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java @@ -57,7 +57,7 @@ public class DataPageInsertFragmentRecord extends PageDeltaRecord { @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { AbstractDataPageIO io = PageIO.getPageIO(pageAddr); - io.addRowFragment(PageIO.getPageId(pageAddr), pageAddr, payload, lastLink, pageMem.pageSize()); + io.addRowFragment(PageIO.getPageId(pageAddr), pageAddr, payload, lastLink, pageMem.realPageSize(groupId())); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java index 2c9a8e7..9b0637d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java @@ -58,7 +58,7 @@ public class DataPageInsertRecord extends PageDeltaRecord { AbstractDataPageIO io = PageIO.getPageIO(pageAddr); - io.addRow(pageAddr, payload, pageMem.pageSize()); + io.addRow(pageAddr, payload, pageMem.realPageSize(groupId())); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java index 5e89f8e..907f4c0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java @@ -60,7 +60,7 @@ public class DataPageMvccMarkUpdatedRecord extends PageDeltaRecord { @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { DataPageIO io = PageIO.getPageIO(pageAddr); - io.updateNewVersion(pageAddr, itemId, pageMem.pageSize(), newMvccCrd, newMvccCntr, newMvccOpCntr); + io.updateNewVersion(pageAddr, itemId, pageMem.realPageSize(groupId()), newMvccCrd, newMvccCntr, newMvccOpCntr); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java index 4a244a1..f3d235d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java @@ -50,7 +50,7 @@ public class DataPageMvccUpdateNewTxStateHintRecord extends PageDeltaRecord { @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { DataPageIO io = PageIO.getPageIO(pageAddr); - io.updateNewTxState(pageAddr, itemId, pageMem.pageSize(), txState); + io.updateNewTxState(pageAddr, itemId, pageMem.realPageSize(groupId()), txState); } /** {@inheritDoc} */
