IGNITE-1915 .NET: Ignite as Entity Framework Second-Level Cache
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/5b31d83f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/5b31d83f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/5b31d83f Branch: refs/heads/master Commit: 5b31d83f38732c8e92807000be858e19387108fd Parents: 2bc234e Author: Pavel Tupitsyn <[email protected]> Authored: Wed Nov 9 18:12:35 2016 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Wed Nov 9 18:12:35 2016 +0300 ---------------------------------------------------------------------- .../dotnet/PlatformDotNetConfigurationEx.java | 16 +- ...PlatformDotNetEntityFrameworkCacheEntry.java | 102 ++ ...formDotNetEntityFrameworkCacheExtension.java | 353 +++++++ .../PlatformDotNetEntityFrameworkCacheKey.java | 164 ++++ ...EntityFrameworkIncreaseVersionProcessor.java | 45 + .../Apache.Ignite.Core.Tests.NuGet.csproj | 11 + .../EntityFrameworkCacheTest.cs | 62 ++ .../packages.config | 2 + .../Cache/CacheAbstractTest.cs | 11 +- .../Apache.Ignite.Core.Tests/TestUtils.cs | 2 + .../Impl/Binary/BinaryObjectHeader.cs | 2 +- .../Apache.Ignite.EntityFramework.Tests.csproj | 96 ++ .../Apache.Ignite.EntityFramework.Tests.snk | Bin 0 -> 596 bytes .../App.config | 71 ++ .../ArrayDbDataReaderTests.cs | 192 ++++ .../DbCachingPolicyTest.cs | 43 + .../EntityFrameworkCacheInitializationTest.cs | 137 +++ .../EntityFrameworkCacheTest.cs | 942 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 39 + .../packages.config | 23 + .../Apache.Ignite.EntityFramework.csproj | 93 ++ .../Apache.Ignite.EntityFramework.nuspec | 57 ++ .../Apache.Ignite.EntityFramework.snk | Bin 0 -> 596 bytes .../DbCachingMode.cs | 48 + .../DbCachingPolicy.cs | 71 ++ .../DbQueryInfo.cs | 78 ++ .../IDbCachingPolicy.cs | 58 ++ .../IgniteDbConfiguration.cs | 240 +++++ .../Impl/ArrayDbDataReader.cs | 305 ++++++ .../Impl/DataReaderField.cs | 74 ++ .../Impl/DataReaderResult.cs | 93 ++ .../Impl/DbCache.cs | 295 ++++++ .../Impl/DbCacheKey.cs | 92 ++ .../Impl/DbCommandDefinitionProxy.cs | 51 + .../Impl/DbCommandInfo.cs | 158 ++++ .../Impl/DbCommandProxy.cs | 263 ++++++ .../Impl/DbProviderServicesProxy.cs | 169 ++++ .../Impl/DbTransactionInterceptor.cs | 134 +++ .../Properties/AssemblyInfo.cs | 41 + .../packages.config | 20 + modules/platforms/dotnet/Apache.Ignite.sln | 28 + 41 files changed, 4673 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationEx.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationEx.java index 34e7ce2..8448733 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationEx.java @@ -21,14 +21,15 @@ import org.apache.ignite.internal.logger.platform.PlatformLogger; import org.apache.ignite.internal.processors.platform.PlatformConfigurationEx; import org.apache.ignite.internal.processors.platform.cache.PlatformCacheExtension; import org.apache.ignite.internal.processors.platform.callback.PlatformCallbackGateway; +import org.apache.ignite.internal.processors.platform.entityframework.PlatformDotNetEntityFrameworkCacheExtension; import org.apache.ignite.internal.processors.platform.memory.PlatformMemoryManagerImpl; import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; import org.apache.ignite.internal.processors.platform.websession.PlatformDotNetSessionCacheExtension; import org.apache.ignite.platform.dotnet.PlatformDotNetConfiguration; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; /** * Extended .Net configuration. @@ -83,13 +84,18 @@ public class PlatformDotNetConfigurationEx extends PlatformDotNetConfiguration i } /** {@inheritDoc} */ - @Override public PlatformLogger logger() { - return logger; + @Nullable @Override public Collection<PlatformCacheExtension> cacheExtensions() { + Collection<PlatformCacheExtension> exts = new ArrayList<>(2); + + exts.add(new PlatformDotNetSessionCacheExtension()); + exts.add(new PlatformDotNetEntityFrameworkCacheExtension()); + + return exts; } /** {@inheritDoc} */ - @Nullable @Override public Collection<PlatformCacheExtension> cacheExtensions() { - return Collections.<PlatformCacheExtension>singleton(new PlatformDotNetSessionCacheExtension()); + @Override public PlatformLogger logger() { + return logger; } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheEntry.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheEntry.java new file mode 100644 index 0000000..676b411 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheEntry.java @@ -0,0 +1,102 @@ +/* + * 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.platform.entityframework; + +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryRawReader; +import org.apache.ignite.binary.BinaryRawWriter; +import org.apache.ignite.binary.BinaryReader; +import org.apache.ignite.binary.BinaryWriter; +import org.apache.ignite.binary.Binarylizable; + +/** + * EntityFramework cache entry. + */ +public class PlatformDotNetEntityFrameworkCacheEntry implements Binarylizable { + /** Dependent entity set names. */ + private String[] entitySets; + + /** Cached data bytes. */ + private byte[] data; + + /** + * Ctor. + */ + public PlatformDotNetEntityFrameworkCacheEntry() { + // No-op. + } + + /** + * Ctor. + * + * @param entitySets Entity set names. + * @param data Data bytes. + */ + PlatformDotNetEntityFrameworkCacheEntry(String[] entitySets, byte[] data) { + this.entitySets = entitySets; + this.data = data; + } + + /** + * @return Dependent entity sets with versions. + */ + public String[] entitySets() { + return entitySets; + } + + /** + * @return Cached data bytes. + */ + public byte[] data() { + return data; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriter writer) throws BinaryObjectException { + final BinaryRawWriter raw = writer.rawWriter(); + + if (entitySets != null) { + raw.writeInt(entitySets.length); + + for (String entitySet : entitySets) + raw.writeString(entitySet); + } + else + raw.writeInt(-1); + + raw.writeByteArray(data); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReader reader) throws BinaryObjectException { + BinaryRawReader raw = reader.rawReader(); + + int cnt = raw.readInt(); + + if (cnt >= 0) { + entitySets = new String[cnt]; + + for (int i = 0; i < cnt; i++) + entitySets[i] = raw.readString(); + } + else + entitySets = null; + + data = raw.readByteArray(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheExtension.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheExtension.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheExtension.java new file mode 100644 index 0000000..d4755de --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheExtension.java @@ -0,0 +1,353 @@ +/* + * 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.platform.entityframework; + +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteCompute; +import org.apache.ignite.cache.CachePeekMode; +import org.apache.ignite.cluster.ClusterGroup; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.binary.BinaryRawReaderEx; +import org.apache.ignite.internal.processors.platform.cache.PlatformCache; +import org.apache.ignite.internal.processors.platform.cache.PlatformCacheExtension; +import org.apache.ignite.internal.processors.platform.memory.PlatformMemory; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.lang.IgniteFuture; +import org.apache.ignite.lang.IgniteInClosure; +import org.apache.ignite.lang.IgniteRunnable; +import org.apache.ignite.resources.IgniteInstanceResource; + +import javax.cache.Cache; +import javax.cache.processor.EntryProcessorResult; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * EntityFramework cache extension. + */ +@SuppressWarnings("unchecked") +public class PlatformDotNetEntityFrameworkCacheExtension implements PlatformCacheExtension { + /** Extension ID. */ + private static final int EXT_ID = 1; + + /** Operation: increment entity set versions. */ + private static final int OP_INVALIDATE_SETS = 1; + + /** Operation: put item async. */ + private static final int OP_PUT_ITEM = 2; + + /** Operation: get item. */ + private static final int OP_GET_ITEM = 3; + + /** Cache key for cleanup node ID. */ + private static final CleanupNodeId CLEANUP_NODE_ID = new CleanupNodeId(); + + /** Indicates whether local cleanup is in progress, per cache name. */ + private final Map<String, Boolean> cleanupFlags = new ConcurrentHashMap<>(); + + /** {@inheritDoc} */ + @Override public int id() { + return EXT_ID; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public long processInOutStreamLong(PlatformCache target, int type, BinaryRawReaderEx reader, + PlatformMemory mem) throws IgniteCheckedException { + switch (type) { + case OP_INVALIDATE_SETS: { + final IgniteCache<String, Long> metaCache = target.rawCache(); + final String dataCacheName = reader.readString(); + + int cnt = reader.readInt(); + + assert cnt > 0; + + final Set<String> entitySetNames = new HashSet(cnt); + + for (int i = 0; i < cnt; i++) + entitySetNames.add(reader.readString()); + + final Map<String, EntryProcessorResult<Long>> curVers = + metaCache.invokeAll(entitySetNames, new PlatformDotNetEntityFrameworkIncreaseVersionProcessor()); + + if (curVers.size() != cnt) + throw new IgniteCheckedException("Failed to update entity set versions [expected=" + cnt + + ", actual=" + curVers.size() + ']'); + + Ignite grid = target.platformContext().kernalContext().grid(); + + startBackgroundCleanup(grid, (IgniteCache<CleanupNodeId, UUID>)(IgniteCache)metaCache, + dataCacheName, curVers); + + return target.writeResult(mem, null); + } + + case OP_PUT_ITEM: { + String query = reader.readString(); + + long[] versions = null; + String[] entitySets = null; + + int cnt = reader.readInt(); + + if (cnt >= 0) { + versions = new long[cnt]; + entitySets = new String[cnt]; + + for (int i = 0; i < cnt; i++) { + versions[i] = reader.readLong(); + entitySets[i] = reader.readString(); + } + } + + byte[] data = reader.readByteArray(); + + PlatformDotNetEntityFrameworkCacheEntry efEntry = + new PlatformDotNetEntityFrameworkCacheEntry(entitySets, data); + + IgniteCache<PlatformDotNetEntityFrameworkCacheKey, PlatformDotNetEntityFrameworkCacheEntry> dataCache + = target.rawCache(); + + PlatformDotNetEntityFrameworkCacheKey key = new PlatformDotNetEntityFrameworkCacheKey(query, versions); + + dataCache.put(key, efEntry); + + return target.writeResult(mem, null); + } + + case OP_GET_ITEM: { + String query = reader.readString(); + + long[] versions = null; + + int cnt = reader.readInt(); + + if (cnt >= 0) { + versions = new long[cnt]; + + for (int i = 0; i < cnt; i++) + versions[i] = reader.readLong(); + } + + IgniteCache<PlatformDotNetEntityFrameworkCacheKey, PlatformDotNetEntityFrameworkCacheEntry> dataCache + = target.rawCache(); + + PlatformDotNetEntityFrameworkCacheKey key = new PlatformDotNetEntityFrameworkCacheKey(query, versions); + + PlatformDotNetEntityFrameworkCacheEntry entry = dataCache.get(key); + + byte[] data = entry == null ? null : entry.data(); + + return target.writeResult(mem, data); + } + } + + throw new IgniteCheckedException("Unsupported operation type: " + type); + } + + /** + * Starts the background cleanup of old cache entries. + * + * @param grid Grid. + * @param metaCache Meta cache. + * @param dataCacheName Data cache name. + * @param currentVersions Current versions. + */ + private void startBackgroundCleanup(Ignite grid, final Cache<CleanupNodeId, UUID> metaCache, + final String dataCacheName, final Map<String, EntryProcessorResult<Long>> currentVersions) { + if (cleanupFlags.containsKey(dataCacheName)) + return; // Current node already performs cleanup. + + if (!trySetGlobalCleanupFlag(grid, metaCache)) + return; + + cleanupFlags.put(dataCacheName, true); + + final ClusterGroup dataNodes = grid.cluster().forDataNodes(dataCacheName); + + IgniteCompute asyncCompute = grid.compute(dataNodes).withAsync(); + + asyncCompute.broadcast(new RemoveOldEntriesRunnable(dataCacheName, currentVersions)); + + asyncCompute.future().listen(new CleanupCompletionListener(metaCache, dataCacheName)); + } + + /** + * Tries to set the global cleanup node id to current node. + * + * @param grid Grid. + * @param metaCache Meta cache. + * + * @return True if successfully set the flag indicating that current node performs the cleanup; otherwise false. + */ + private boolean trySetGlobalCleanupFlag(Ignite grid, final Cache<CleanupNodeId, UUID> metaCache) { + final UUID localNodeId = grid.cluster().localNode().id(); + + while (true) { + // Get the node performing cleanup. + UUID nodeId = metaCache.get(CLEANUP_NODE_ID); + + if (nodeId == null) { + if (metaCache.putIfAbsent(CLEANUP_NODE_ID, localNodeId)) + return true; // Successfully reserved cleanup to local node. + + // Failed putIfAbsent: someone else may have started cleanup. Retry the check. + continue; + } + + if (nodeId.equals(localNodeId)) + return false; // Current node already performs cleanup. + + if (grid.cluster().node(nodeId) != null) + return false; // Another node already performs cleanup and is alive. + + // Node that performs cleanup has disconnected. + if (metaCache.replace(CLEANUP_NODE_ID, nodeId, localNodeId)) + return true; // Successfully replaced disconnected node id with our id. + + // Replace failed: someone else started cleanup. + return false; + } + } + + /** + * Removes old cache entries locally. + * + * @param ignite Ignite. + * @param dataCacheName Cache name. + * @param currentVersions Current versions. + */ + private static void removeOldEntries(final Ignite ignite, final String dataCacheName, + final Map<String, EntryProcessorResult<Long>> currentVersions) { + + IgniteCache<PlatformDotNetEntityFrameworkCacheKey, PlatformDotNetEntityFrameworkCacheEntry> cache = + ignite.cache(dataCacheName); + + Set<PlatformDotNetEntityFrameworkCacheKey> keysToRemove = new TreeSet<>(); + + ClusterNode localNode = ignite.cluster().localNode(); + + for (Cache.Entry<PlatformDotNetEntityFrameworkCacheKey, PlatformDotNetEntityFrameworkCacheEntry> cacheEntry : + cache.localEntries(CachePeekMode.ALL)) { + // Check if we are on a primary node for the key, since we use CachePeekMode.ALL + // and we don't want to process backup entries. + if (!ignite.affinity(dataCacheName).isPrimary(localNode, cacheEntry.getKey())) + continue; + + long[] versions = cacheEntry.getKey().versions(); + String[] entitySets = cacheEntry.getValue().entitySets(); + + for (int i = 0; i < entitySets.length; i++) { + EntryProcessorResult<Long> curVer = currentVersions.get(entitySets[i]); + + if (curVer != null && versions[i] < curVer.get()) + keysToRemove.add(cacheEntry.getKey()); + } + } + + cache.removeAll(keysToRemove); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(PlatformDotNetEntityFrameworkCacheExtension.class, this); + } + + /** + * Cache key for cleanup node id. + */ + private static class CleanupNodeId { + // No-op. + } + + /** + * Old entries remover. + */ + private static class RemoveOldEntriesRunnable implements IgniteRunnable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final String dataCacheName; + + /** */ + private final Map<String, EntryProcessorResult<Long>> currentVersions; + + /** Inject Ignite. */ + @IgniteInstanceResource + private Ignite ignite; + + /** + * Ctor. + * + * @param dataCacheName Name of the cache to clean up. + * @param currentVersions Map of current entity set versions. + */ + private RemoveOldEntriesRunnable(String dataCacheName, + Map<String, EntryProcessorResult<Long>> currentVersions) { + this.dataCacheName = dataCacheName; + this.currentVersions = currentVersions; + } + + /** {@inheritDoc} */ + @Override public void run() { + removeOldEntries(ignite, dataCacheName, currentVersions); + } + } + + /** + * Cleanup completion listener. + */ + private class CleanupCompletionListener implements IgniteInClosure<IgniteFuture<Object>> { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Cache<CleanupNodeId, UUID> metaCache; + + /** */ + private final String dataCacheName; + + /** + * Ctor. + * + * @param metaCache Metadata cache. + * @param dataCacheName Data cache name. + */ + private CleanupCompletionListener(Cache<CleanupNodeId, UUID> metaCache, String dataCacheName) { + this.metaCache = metaCache; + this.dataCacheName = dataCacheName; + } + + /** {@inheritDoc} */ + @Override public void apply(IgniteFuture<Object> future) { + // Reset distributed cleanup flag. + metaCache.remove(CLEANUP_NODE_ID); + + // Reset local cleanup flag. + cleanupFlags.remove(dataCacheName); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheKey.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheKey.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheKey.java new file mode 100644 index 0000000..60fdaec --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkCacheKey.java @@ -0,0 +1,164 @@ +/* + * 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.platform.entityframework; + +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryRawReader; +import org.apache.ignite.binary.BinaryRawWriter; +import org.apache.ignite.binary.BinaryReader; +import org.apache.ignite.binary.BinaryWriter; +import org.apache.ignite.binary.Binarylizable; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * EntityFramework cache key: query + versions. + */ +@SuppressWarnings("WeakerAccess") +public class PlatformDotNetEntityFrameworkCacheKey + implements Binarylizable, Comparable<PlatformDotNetEntityFrameworkCacheKey> { + /** Query text. */ + private String query; + + /** Entity set versions. */ + private long[] versions; + + /** + * Ctor. + */ + public PlatformDotNetEntityFrameworkCacheKey() { + // No-op. + } + + /** + * Ctor. + * + * @param query Query text. + * @param versions Versions. + */ + PlatformDotNetEntityFrameworkCacheKey(String query, long[] versions) { + assert query != null; + + this.query = query; + this.versions = versions; + } + + /** + * Gets the query text. + * + * @return Query text. + */ + public String query() { + return query; + } + + /** + * Gets the entity set versions. + * + * @return Entity set versions. + */ + public long[] versions() { + return versions; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + PlatformDotNetEntityFrameworkCacheKey key = (PlatformDotNetEntityFrameworkCacheKey)o; + + //noinspection SimplifiableIfStatement + if (!query.equals(key.query)) + return false; + + return Arrays.equals(versions, key.versions); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + int result = query.hashCode(); + + result = 31 * result + Arrays.hashCode(versions); + + return result; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriter writer) throws BinaryObjectException { + final BinaryRawWriter raw = writer.rawWriter(); + + raw.writeString(query); + + if (versions != null) { + raw.writeInt(versions.length); + + for (long ver : versions) + raw.writeLong(ver); + } + else + raw.writeInt(-1); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReader reader) throws BinaryObjectException { + BinaryRawReader raw = reader.rawReader(); + + query = raw.readString(); + + int cnt = raw.readInt(); + + if (cnt >= 0) { + versions = new long[cnt]; + + for (int i = 0; i < cnt; i++) + versions[i] = raw.readLong(); + } + else + versions = null; + } + + /** {@inheritDoc} */ + @Override public int compareTo(@NotNull PlatformDotNetEntityFrameworkCacheKey o) { + int cmpQuery = query.compareTo(o.query); + + if (cmpQuery != 0) + return cmpQuery; + + if (versions == null) { + return o.versions == null ? 0 : -1; + } + + if (o.versions == null) + return 1; + + assert versions.length == o.versions.length; + + for (int i = 0; i < versions.length; i++) { + if (versions[i] != o.versions[i]) { + return versions[i] > o.versions[i] ? 1 : -1; + } + } + + return 0; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkIncreaseVersionProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkIncreaseVersionProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkIncreaseVersionProcessor.java new file mode 100644 index 0000000..f10138a --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/entityframework/PlatformDotNetEntityFrameworkIncreaseVersionProcessor.java @@ -0,0 +1,45 @@ +/* + * 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.platform.entityframework; + +import org.apache.ignite.cache.CacheEntryProcessor; + +import javax.cache.processor.EntryProcessorException; +import javax.cache.processor.MutableEntry; + +/** + * Entry processor that increments entity set version number. + */ +public class PlatformDotNetEntityFrameworkIncreaseVersionProcessor implements CacheEntryProcessor<String, Long, Long> { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override public Long process(MutableEntry<String, Long> entry, Object... args) throws EntryProcessorException { + Long val = entry.getValue(); + + if (val == null) + val = 0L; + + val++; + + entry.setValue(val); + + return val; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj index a71d1d8..4452ac7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/Apache.Ignite.Core.Tests.NuGet.csproj @@ -95,6 +95,16 @@ <HintPath>packages\Apache.Ignite.Log4Net.1.8.0\lib\net40\Apache.Ignite.Log4Net.dll</HintPath> <Private>True</Private> </Reference> + <Reference Include="Apache.Ignite.EntityFramework"> + <SpecificVersion>False</SpecificVersion> + <HintPath>packages\Apache.Ignite.EntityFramework.1.8.0\lib\net40\Apache.Ignite.EntityFramework.dll</HintPath> + <Private>True</Private> + </Reference> + <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> + <HintPath>packages\EntityFramework.6.1.0\lib\net40\EntityFramework.dll</HintPath> + <SpecificVersion>False</SpecificVersion> + <Private>True</Private> + </Reference> <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <HintPath>packages\NLog.4.3.7\lib\net40\NLog.dll</HintPath> <Private>True</Private> @@ -127,6 +137,7 @@ <Compile Include="AspNetTest.cs" /> <Compile Include="ComputeTest.cs" /> <Compile Include="SchemaTest.cs" /> + <Compile Include="EntityFrameworkCacheTest.cs" /> <Compile Include="StartupTest.cs" /> <Compile Include="CacheTest.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/EntityFrameworkCacheTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/EntityFrameworkCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/EntityFrameworkCacheTest.cs new file mode 100644 index 0000000..b4781ce --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/EntityFrameworkCacheTest.cs @@ -0,0 +1,62 @@ +/* + * 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. + */ + +namespace Apache.Ignite.Core.Tests.NuGet +{ + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.EntityFramework; + using NUnit.Framework; + + /// <summary> + /// Tests the EntityFramework integration. + /// </summary> + public class EntityFrameworkCacheTest + { + /// <summary> + /// Tests cache startup and basic operation. + /// </summary> + [Test] + public void TestStartupPutGet() + { + var cfg = new IgniteConfiguration + { + DiscoverySpi = TestUtil.GetLocalDiscoverySpi(), + GridName = "myGrid" + }; + + // ReSharper disable once ObjectCreationAsStatement + new IgniteDbConfiguration(cfg, + new CacheConfiguration("efMetaCache") {AtomicityMode = CacheAtomicityMode.Transactional}, + new CacheConfiguration("efDataCache"), null); + + var ignite = Ignition.GetIgnite(cfg.GridName); + Assert.IsNotNull(ignite); + + Assert.IsNotNull(ignite.GetCache<string, object>("efMetaCache")); + Assert.IsNotNull(ignite.GetCache<string, object>("efDataCache")); + } + + /// <summary> + /// Test teardown. + /// </summary> + [TearDown] + public void TearDown() + { + Ignition.StopAll(true); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config index 80454e0..a7c48f3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.NuGet/packages.config @@ -22,8 +22,10 @@ <package id="Apache.Ignite.NLog" version="1.8.0" targetFramework="net40" /> <package id="Apache.Ignite.Log4Net" version="1.8.0" targetFramework="net40" /> <package id="Apache.Ignite.Schema" version="1.8.0" targetFramework="net40" /> + <package id="Apache.Ignite.EntityFramework" version="1.8.0" targetFramework="net40" /> <package id="NLog" version="4.3.7" targetFramework="net40" /> <package id="NUnit.Runners" version="2.6.3" targetFramework="net40" /> <package id="Remotion.Linq" version="2.0.1" targetFramework="net40" /> <package id="log4net" version="2.0.5" targetFramework="net40" /> + <package id="EntityFramework" version="6.1.0" targetFramework="net40" /> </packages> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs index 26c1096..2a2d588 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs @@ -956,10 +956,17 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.IsFalse(cache0.ContainsKey(key0)); Assert.IsFalse(cache0.ContainsKey(key1)); + // Test sliding expiration cache0.Put(key0, key0); cache0.Put(key1, key1); - cache.Get(key0); - cache.Get(key1); + for (var i = 0; i < 3; i++) + { + Thread.Sleep(50); + + // Prolong expiration by touching the entry + cache.Get(key0); + cache.Get(key1); + } Assert.IsTrue(cache0.ContainsKey(key0)); Assert.IsTrue(cache0.ContainsKey(key1)); Thread.Sleep(200); http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs index 4ff3fea..5a9c824 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs @@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Tests using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Apache.Ignite.Core.Discovery.Tcp; @@ -346,6 +347,7 @@ namespace Apache.Ignite.Core.Tests /// <summary> /// Runs the test in new process. /// </summary> + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] public static void RunTestInNewProcess(string fixtureName, string testName) { var procStart = new ProcessStartInfo http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs index bb5c207..0e5ad2a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs @@ -265,7 +265,7 @@ namespace Apache.Ignite.Core.Impl.Binary Debug.Assert(hdr.Version == BinaryUtils.ProtoVer); Debug.Assert(hdr.SchemaOffset <= hdr.Length); - Debug.Assert(hdr.SchemaOffset >= Size); + Debug.Assert(hdr.SchemaOffset >= Size || !hdr.HasSchema); } else http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.csproj new file mode 100644 index 0000000..9711087 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.csproj @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{CDA5700E-78F3-4A9E-A9B0-704CBE94651C}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Apache.Ignite.EntityFramework.Tests</RootNamespace> + <AssemblyName>Apache.Ignite.EntityFramework.Tests</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <SignAssembly>true</SignAssembly> + </PropertyGroup> + <PropertyGroup> + <AssemblyOriginatorKeyFile>Apache.Ignite.EntityFramework.Tests.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="EntityFramework"> + <HintPath>..\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.dll</HintPath> + </Reference> + <Reference Include="EntityFramework.SqlServerCompact"> + <HintPath>..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net40\EntityFramework.SqlServerCompact.dll</HintPath> + </Reference> + <Reference Include="nunit.framework"> + <HintPath>..\packages\NUnit.Runners.2.6.3\tools\nunit.framework.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll</HintPath> + </Reference> + <Reference Include="System.Transactions" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ArrayDbDataReaderTests.cs" /> + <Compile Include="DbCachingPolicyTest.cs" /> + <Compile Include="EntityFrameworkCacheInitializationTest.cs" /> + <Compile Include="EntityFrameworkCacheTest.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Apache.Ignite.Core.Tests\Apache.Ignite.Core.Tests.csproj"> + <Project>{6a62f66c-da5b-4fbb-8ce7-a95f740fdc7a}</Project> + <Name>Apache.Ignite.Core.Tests</Name> + </ProjectReference> + <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj"> + <Project>{4cd2f726-7e2b-46c4-a5ba-057bb82eecb6}</Project> + <Name>Apache.Ignite.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Apache.Ignite.EntityFramework\Apache.Ignite.EntityFramework.csproj"> + <Project>{c558518a-c1a0-4224-aaa9-a8688474b4dc}</Project> + <Name>Apache.Ignite.EntityFramework</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="Apache.Ignite.EntityFramework.Tests.snk" /> + <None Include="App.config" /> + <None Include="packages.config"> + <SubType>Designer</SubType> + </None> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <PropertyGroup> + <PostBuildEvent> + if not exist "$(TargetDir)x86" md "$(TargetDir)x86" + xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86" + if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" + xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" + </PostBuildEvent> + </PropertyGroup> +</Project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.snk ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.snk b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.snk new file mode 100644 index 0000000..5ef85a6 Binary files /dev/null and b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/Apache.Ignite.EntityFramework.Tests.snk differ http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/App.config ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/App.config b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/App.config new file mode 100644 index 0000000..3527920 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/App.config @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- + 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. +--> +<configuration> + <configSections> + <section name="igniteConfiguration" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" /> + <section name="igniteConfiguration2" type="Apache.Ignite.Core.IgniteConfigurationSection, Apache.Ignite.Core" /> + <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> + </configSections> + <runtime> + <gcServer enabled="true" /> + </runtime> + + <igniteConfiguration xmlns="http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection" gridName="myGrid1"> + <discoverySpi type="TcpDiscoverySpi"> + <ipFinder type="TcpDiscoveryStaticIpFinder"> + <endpoints> + <string>127.0.0.1:47500</string> + </endpoints> + </ipFinder> + </discoverySpi> + <cacheConfiguration> + <cacheConfiguration name="cacheName" /> + </cacheConfiguration> + </igniteConfiguration> + + <igniteConfiguration2 gridName="myGrid2" localhost="127.0.0.1"> + <discoverySpi type="TcpDiscoverySpi"> + <ipFinder type="TcpDiscoveryStaticIpFinder"> + <endpoints> + <string>127.0.0.1:47500</string> + </endpoints> + </ipFinder> + </discoverySpi> + <cacheConfiguration> + <cacheConfiguration name="cacheName2" atomicityMode="Transactional" /> + </cacheConfiguration> + </igniteConfiguration2> + + <entityFramework> + <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework"> + <parameters> + <parameter value="System.Data.SqlServerCe.4.0" /> + </parameters> + </defaultConnectionFactory> + <providers> + <provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" /> + </providers> + </entityFramework> + + <system.data> + <DbProviderFactories> + <remove invariant="System.Data.SqlServerCe.4.0" /> + <add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" /> + </DbProviderFactories> + </system.data> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/ArrayDbDataReaderTests.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/ArrayDbDataReaderTests.cs b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/ArrayDbDataReaderTests.cs new file mode 100644 index 0000000..f67fed4 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/ArrayDbDataReaderTests.cs @@ -0,0 +1,192 @@ +/* + * 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. + */ + +namespace Apache.Ignite.EntityFramework.Tests +{ + using System; + using System.Linq; + using Apache.Ignite.EntityFramework.Impl; + using NUnit.Framework; + + /// <summary> + /// Tests for <see cref="ArrayDbDataReader"/>. + /// </summary> + public class ArrayDbDataReaderTests + { + /// <summary> + /// Tests the reader. + /// </summary> + [Test] + public void TestReader() + { + var dateTime = DateTime.Now; + var guid = Guid.NewGuid(); + + var data = new[] + { + new object[] + { + (byte) 1, (short) 2, 3, (long) 4, (float) 5, (double) 6, (decimal) 7, "8", '9', dateTime, + guid, false, new byte[] {1,2}, new[] {'a','b'} + } + }; + + var schema = new [] + { + new DataReaderField("fbyte", typeof(byte), "by"), + new DataReaderField("fshort", typeof(short), "sh"), + new DataReaderField("fint", typeof(int), "in"), + new DataReaderField("flong", typeof(long), "lo"), + new DataReaderField("ffloat", typeof(float), "fl"), + new DataReaderField("fdouble", typeof(double), "do"), + new DataReaderField("fdecimal", typeof(decimal), "de"), + new DataReaderField("fstring", typeof(string), "st"), + new DataReaderField("fchar", typeof(char), "ch"), + new DataReaderField("fDateTime", typeof(DateTime), "Da"), + new DataReaderField("fGuid", typeof(Guid), "Gu"), + new DataReaderField("fbool", typeof(bool), "bo"), + new DataReaderField("fbytes", typeof(byte[]), "bb"), + new DataReaderField("fchars", typeof(char[]), "cc"), + }; + + // Create reader, + var reader = new ArrayDbDataReader(data, schema); + + // Check basic props. + Assert.IsTrue(reader.Read()); + Assert.AreEqual(0, reader.Depth); + Assert.AreEqual(-1, reader.RecordsAffected); + Assert.AreEqual(14, reader.FieldCount); + Assert.AreEqual(14, reader.VisibleFieldCount); + Assert.IsFalse(reader.IsClosed); + Assert.IsTrue(reader.HasRows); + + // Check reading. + var data2 = new object[14]; + Assert.AreEqual(14, reader.GetValues(data2)); + Assert.AreEqual(data[0], data2); + + Assert.AreEqual(1, reader.GetByte(reader.GetOrdinal("fbyte"))); + Assert.AreEqual("by", reader.GetDataTypeName(0)); + Assert.AreEqual(typeof(byte), reader.GetFieldType(0)); + Assert.AreEqual("fbyte", reader.GetName(0)); + Assert.AreEqual(1, reader["fbyte"]); + Assert.AreEqual(1, reader[0]); + + Assert.AreEqual(2, reader.GetInt16(reader.GetOrdinal("fshort"))); + Assert.AreEqual("sh", reader.GetDataTypeName(1)); + Assert.AreEqual(typeof(short), reader.GetFieldType(1)); + Assert.AreEqual("fshort", reader.GetName(1)); + Assert.AreEqual(2, reader["fshort"]); + Assert.AreEqual(2, reader[1]); + + Assert.AreEqual(3, reader.GetInt32(reader.GetOrdinal("fint"))); + Assert.AreEqual("in", reader.GetDataTypeName(2)); + Assert.AreEqual(typeof(int), reader.GetFieldType(2)); + Assert.AreEqual("fint", reader.GetName(2)); + Assert.AreEqual(3, reader["fint"]); + Assert.AreEqual(3, reader[2]); + + Assert.AreEqual(4, reader.GetInt64(reader.GetOrdinal("flong"))); + Assert.AreEqual("lo", reader.GetDataTypeName(3)); + Assert.AreEqual(typeof(long), reader.GetFieldType(3)); + Assert.AreEqual("flong", reader.GetName(3)); + Assert.AreEqual(4, reader["flong"]); + Assert.AreEqual(4, reader[3]); + + Assert.AreEqual(5, reader.GetFloat(reader.GetOrdinal("ffloat"))); + Assert.AreEqual("fl", reader.GetDataTypeName(4)); + Assert.AreEqual(typeof(float), reader.GetFieldType(4)); + Assert.AreEqual("ffloat", reader.GetName(4)); + Assert.AreEqual(5, reader["ffloat"]); + Assert.AreEqual(5, reader[4]); + + Assert.AreEqual(6, reader.GetDouble(reader.GetOrdinal("fdouble"))); + Assert.AreEqual("do", reader.GetDataTypeName(5)); + Assert.AreEqual(typeof(double), reader.GetFieldType(5)); + Assert.AreEqual("fdouble", reader.GetName(5)); + Assert.AreEqual(6, reader["fdouble"]); + Assert.AreEqual(6, reader[5]); + + Assert.AreEqual(7, reader.GetDecimal(reader.GetOrdinal("fdecimal"))); + Assert.AreEqual("de", reader.GetDataTypeName(6)); + Assert.AreEqual(typeof(decimal), reader.GetFieldType(6)); + Assert.AreEqual("fdecimal", reader.GetName(6)); + Assert.AreEqual(7, reader["fdecimal"]); + Assert.AreEqual(7, reader[6]); + + Assert.AreEqual("8", reader.GetString(reader.GetOrdinal("fstring"))); + Assert.AreEqual("st", reader.GetDataTypeName(7)); + Assert.AreEqual(typeof(string), reader.GetFieldType(7)); + Assert.AreEqual("fstring", reader.GetName(7)); + Assert.AreEqual("8", reader["fstring"]); + Assert.AreEqual("8", reader[7]); + + Assert.AreEqual('9', reader.GetChar(reader.GetOrdinal("fchar"))); + Assert.AreEqual("ch", reader.GetDataTypeName(8)); + Assert.AreEqual(typeof(char), reader.GetFieldType(8)); + Assert.AreEqual("fchar", reader.GetName(8)); + Assert.AreEqual('9', reader["fchar"]); + Assert.AreEqual('9', reader[8]); + + Assert.AreEqual(dateTime, reader.GetDateTime(reader.GetOrdinal("fDateTime"))); + Assert.AreEqual("Da", reader.GetDataTypeName(9)); + Assert.AreEqual(typeof(DateTime), reader.GetFieldType(9)); + Assert.AreEqual("fDateTime", reader.GetName(9)); + Assert.AreEqual(dateTime, reader["fDateTime"]); + Assert.AreEqual(dateTime, reader[9]); + + Assert.AreEqual(guid, reader.GetGuid(reader.GetOrdinal("fGuid"))); + Assert.AreEqual("Gu", reader.GetDataTypeName(10)); + Assert.AreEqual(typeof(Guid), reader.GetFieldType(10)); + Assert.AreEqual("fGuid", reader.GetName(10)); + Assert.AreEqual(guid, reader["fGuid"]); + Assert.AreEqual(guid, reader[10]); + + Assert.AreEqual(false, reader.GetBoolean(reader.GetOrdinal("fbool"))); + Assert.AreEqual("bo", reader.GetDataTypeName(11)); + Assert.AreEqual(typeof(bool), reader.GetFieldType(11)); + Assert.AreEqual("fbool", reader.GetName(11)); + Assert.AreEqual(false, reader["fbool"]); + Assert.AreEqual(false, reader[11]); + + var bytes = new byte[2]; + Assert.AreEqual(2, reader.GetBytes(reader.GetOrdinal("fbytes"),0, bytes, 0, 2)); + Assert.AreEqual(data[0][12], bytes); + Assert.AreEqual("bb", reader.GetDataTypeName(12)); + Assert.AreEqual(typeof(byte[]), reader.GetFieldType(12)); + Assert.AreEqual("fbytes", reader.GetName(12)); + Assert.AreEqual(data[0][12], reader["fbytes"]); + Assert.AreEqual(data[0][12], reader[12]); + + var chars = new char[2]; + Assert.AreEqual(2, reader.GetChars(reader.GetOrdinal("fchars"),0, chars, 0, 2)); + Assert.AreEqual(data[0][13], chars); + Assert.AreEqual("cc", reader.GetDataTypeName(13)); + Assert.AreEqual(typeof(char[]), reader.GetFieldType(13)); + Assert.AreEqual("fchars", reader.GetName(13)); + Assert.AreEqual(data[0][13], reader["fchars"]); + Assert.AreEqual(data[0][13], reader[13]); + + Assert.IsFalse(Enumerable.Range(0, 14).Any(x => reader.IsDBNull(x))); + + // Close. + reader.Close(); + Assert.IsTrue(reader.IsClosed); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/DbCachingPolicyTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/DbCachingPolicyTest.cs b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/DbCachingPolicyTest.cs new file mode 100644 index 0000000..c9456b6 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/DbCachingPolicyTest.cs @@ -0,0 +1,43 @@ +/* + * 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. + */ + +namespace Apache.Ignite.EntityFramework.Tests +{ + using System; + using Apache.Ignite.EntityFramework; + using NUnit.Framework; + + /// <summary> + /// Tests for <see cref="DbCachingPolicy"/>. + /// </summary> + public class DbCachingPolicyTest + { + /// <summary> + /// Tests the default implementation. + /// </summary> + [Test] + public void TestDefaultImpl() + { + var plc = new DbCachingPolicy(); + + Assert.IsTrue(plc.CanBeCached(null)); + Assert.IsTrue(plc.CanBeCached(null, 0)); + Assert.AreEqual(TimeSpan.MaxValue, plc.GetExpirationTimeout(null)); + Assert.AreEqual(DbCachingMode.ReadWrite, plc.GetCachingMode(null)); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b31d83f/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/EntityFrameworkCacheInitializationTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/EntityFrameworkCacheInitializationTest.cs b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/EntityFrameworkCacheInitializationTest.cs new file mode 100644 index 0000000..36b1c2b --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.EntityFramework.Tests/EntityFrameworkCacheInitializationTest.cs @@ -0,0 +1,137 @@ +/* + * 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. + */ + +namespace Apache.Ignite.EntityFramework.Tests +{ + using System; + using Apache.Ignite.Core; + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Tests; + using Apache.Ignite.EntityFramework; + using NUnit.Framework; + + /// <summary> + /// Tests the EF cache provider. + /// </summary> + public class EntityFrameworkCacheInitializationTest + { + /// <summary> + /// Fixture tear down. + /// </summary> + [TestFixtureTearDown] + public void TestFixtureTearDown() + { + Ignition.StopAll(true); + } + + /// <summary> + /// Tests the IgniteDbConfiguration. + /// </summary> + [Test] + public void TestConfigurationAndStartup() + { + Environment.SetEnvironmentVariable("IGNITE_NATIVE_TEST_CLASSPATH", "true"); + + Assert.IsNull(Ignition.TryGetIgnite()); + + // Test default config (picks up app.config section). + CheckCacheAndStop("myGrid1", IgniteDbConfiguration.DefaultCacheNamePrefix, new IgniteDbConfiguration()); + + // Specific config section. + CheckCacheAndStop("myGrid2", "cacheName2", + new IgniteDbConfiguration("igniteConfiguration2", "cacheName2", null)); + + // Specific config section, nonexistent cache. + CheckCacheAndStop("myGrid2", "newCache", + new IgniteDbConfiguration("igniteConfiguration2", "newCache", null)); + + // In-code configuration. + CheckCacheAndStop("myGrid3", "myCache", + new IgniteDbConfiguration(new IgniteConfiguration + { + GridName = "myGrid3", + }, new CacheConfiguration("myCache_metadata") + { + CacheMode = CacheMode.Replicated, + AtomicityMode = CacheAtomicityMode.Transactional + }, + new CacheConfiguration("myCache_data") {CacheMode = CacheMode.Replicated}, null), + CacheMode.Replicated); + + // Existing instance. + var ignite = Ignition.Start(TestUtils.GetTestConfiguration()); + CheckCacheAndStop(null, "123", new IgniteDbConfiguration(ignite, + new CacheConfiguration("123_metadata") + { + Backups = 1, + AtomicityMode = CacheAtomicityMode.Transactional + }, + new CacheConfiguration("123_data"), null)); + + // Non-tx meta cache. + var ex = Assert.Throws<IgniteException>(() => CheckCacheAndStop(null, "123", + new IgniteDbConfiguration(TestUtils.GetTestConfiguration(), + new CacheConfiguration("123_metadata"), + new CacheConfiguration("123_data"), null))); + + Assert.AreEqual("EntityFramework meta cache should be Transactional.", ex.Message); + + // Same cache names. + var ex2 = Assert.Throws<ArgumentException>(() => CheckCacheAndStop(null, "abc", + new IgniteDbConfiguration(TestUtils.GetTestConfiguration(), + new CacheConfiguration("abc"), + new CacheConfiguration("abc"), null))); + + Assert.IsTrue(ex2.Message.Contains("Meta and Data cache can't have the same name.")); + } + + /// <summary> + /// Checks that specified cache exists and stops all Ignite instances. + /// </summary> + // ReSharper disable once UnusedParameter.Local + private static void CheckCacheAndStop(string gridName, string cacheName, IgniteDbConfiguration cfg, + CacheMode cacheMode = CacheMode.Partitioned) + { + try + { + Assert.IsNotNull(cfg); + + var ignite = Ignition.TryGetIgnite(gridName); + Assert.IsNotNull(ignite); + + var metaCache = ignite.GetCache<object, object>(cacheName + "_metadata"); + Assert.IsNotNull(metaCache); + Assert.AreEqual(cacheMode, metaCache.GetConfiguration().CacheMode); + + if (cacheMode == CacheMode.Partitioned) + Assert.AreEqual(1, metaCache.GetConfiguration().Backups); + + var dataCache = ignite.GetCache<object, object>(cacheName + "_data"); + Assert.IsNotNull(dataCache); + Assert.AreEqual(cacheMode, dataCache.GetConfiguration().CacheMode); + + if (cacheMode == CacheMode.Partitioned) + Assert.AreEqual(0, dataCache.GetConfiguration().Backups); + } + finally + { + Ignition.StopAll(true); + } + } + } +}
