You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2016/08/03 11:28:45 UTC

[03/48] ignite git commit: IGNITE-3561: .NET: Improved distributed joins API for LINQ, added more tests. This closes #893. This closes #900.

IGNITE-3561: .NET: Improved distributed joins API for LINQ, added more tests. This closes #893. This closes #900.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/9a808386
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/9a808386
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/9a808386

Branch: refs/heads/ignite-3443
Commit: 9a8083860ed61dde981cb6da65de869dc4205ae0
Parents: 42f42ea
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Wed Jul 27 13:42:30 2016 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Jul 27 13:42:30 2016 +0300

----------------------------------------------------------------------
 .../Cache/Query/CacheLinqTest.cs                | 55 ++++++++++--
 .../Cache/Query/CacheQueriesTest.cs             | 29 ++++---
 .../Apache.Ignite.Linq.csproj                   |  1 +
 .../Apache.Ignite.Linq/CacheExtensions.cs       | 23 +----
 .../Apache.Ignite.Linq/Impl/CacheQueryable.cs   | 15 ++--
 .../dotnet/Apache.Ignite.Linq/QueryOptions.cs   | 91 ++++++++++++++++++++
 6 files changed, 165 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
index f76a74c..679f03a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
@@ -36,7 +36,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
-    using Apache.Ignite.Core.Common;
     using Apache.Ignite.Linq;
     using NUnit.Framework;
 
@@ -955,7 +954,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             var cache = GetPersonCache();
 
             // Check regular query
-            var query = (ICacheQueryable) cache.AsCacheQueryable(true, null, 999, false, true).Where(x => x.Key > 10);
+            var query = (ICacheQueryable) cache.AsCacheQueryable(new QueryOptions
+            {
+                Local = true,
+                PageSize = 999,
+                EnforceJoinOrder = true
+            }).Where(x => x.Key > 10);
 
             Assert.AreEqual(cache.Name, query.CacheName);
             Assert.AreEqual(cache.Ignite, query.Ignite);
@@ -983,14 +987,10 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             Assert.IsFalse(fq.EnforceJoinOrder);
 
             // Check distributed joins flag propagation
-            var distrQuery = cache.AsCacheQueryable(true, null, 999, true, true).Where(x => x.Key > 10);
+            var distrQuery = cache.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true})
+                .Where(x => x.Key > 10);
             query = (ICacheQueryable) distrQuery;
             Assert.IsTrue(query.GetFieldsQuery().EnableDistributedJoins);
-
-            // Easy check that EnableDistributedJoins is propagated to Java: it throws an error on replicated cache
-            var ex = Assert.Throws<IgniteException>(() => Assert.AreEqual(0, distrQuery.ToArray().Length));
-            Assert.AreEqual("Queries using distributed JOINs have to be run on partitioned cache, not on replicated.",
-                ex.Message);
         }
 
         /// <summary>
@@ -1022,6 +1022,45 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         }
 
         /// <summary>
+        /// Tests the distributed joins.
+        /// </summary>
+        [Test]
+        public void TestDistributedJoins()
+        {
+            var ignite = Ignition.GetIgnite();
+
+            // Create and populate partitioned caches
+            var personCache = ignite.CreateCache<int, Person>(new CacheConfiguration("partitioned_persons",
+                new QueryEntity(typeof(int), typeof(Person))));
+
+            personCache.PutAll(GetSecondPersonCache().ToDictionary(x => x.Key, x => x.Value));
+
+            var roleCache = ignite.CreateCache<int, Role>(new CacheConfiguration("partitioned_roles",
+                    new QueryEntity(typeof(int), typeof(Role))));
+
+            roleCache.PutAll(GetRoleCache().ToDictionary(x => x.Key.Foo, x => x.Value));
+
+            // Test non-distributed join: returns partial results
+            var persons = personCache.AsCacheQueryable();
+            var roles = roleCache.AsCacheQueryable();
+
+            var res = persons.Join(roles, person => person.Key - PersonCount, role => role.Key, (person, role) => role)
+                .ToArray();
+
+            Assert.Greater(res.Length, 0);
+            Assert.Less(res.Length, RoleCount);
+
+            // Test distributed join: returns complete results
+            persons = personCache.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true});
+            roles = roleCache.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true});
+
+            res = persons.Join(roles, person => person.Key - PersonCount, role => role.Key, (person, role) => role)
+                .ToArray();
+
+            Assert.AreEqual(RoleCount, res.Length);
+        }
+
+        /// <summary>
         /// Gets the person cache.
         /// </summary>
         /// <returns></returns>

http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
index 7bfd202..a8ffe13 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
@@ -552,31 +552,36 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         [Test]
         public void TestDistributedJoins()
         {
-            // Easy check that EnableDistributedJoins is propagated to Java: it throws an error on replicated cache
             var cache = GetIgnite(0).GetOrCreateCache<int, QueryPerson>(
                 new CacheConfiguration("replicatedCache")
                 {
-                    CacheMode = CacheMode.Replicated,
                     QueryEntities = new[]
                     {
-                        new QueryEntity(typeof(QueryPerson))
+                        new QueryEntity(typeof(int), typeof(QueryPerson))
                         {
                             Fields = new[] {new QueryField("age", typeof(int))}
                         }
                     }
                 });
 
-            cache[1] = new QueryPerson("Test", 150);
+            const int count = 100;
 
-            // Distributed joins disabled: query works
-            var qry = new SqlQuery(typeof(QueryPerson), "age < 50");
-            Assert.AreEqual(0, cache.Query(qry).GetAll().Count);
+            cache.PutAll(Enumerable.Range(0, count).ToDictionary(x => x, x => new QueryPerson("Name" + x, x)));
 
-            // Distributed joins enabled: query fails
-            qry.EnableDistributedJoins = true;
-            var ex = Assert.Throws<IgniteException>(() => Assert.AreEqual(0, cache.Query(qry).GetAll().Count));
-            Assert.AreEqual("Queries using distributed JOINs have to be run on partitioned cache, not on replicated.",
-                ex.Message);
+            // Test non-distributed join: returns partial results
+            var sql = "select T0.Age from QueryPerson as T0 " +
+                      "inner join QueryPerson as T1 on ((? - T1.Age - 1) = T0._key)";
+
+            var res = cache.QueryFields(new SqlFieldsQuery(sql, count)).GetAll().Distinct().Count();
+
+            Assert.Greater(res, 0);
+            Assert.Less(res, count);
+
+            // Test distributed join: returns complete results
+            res = cache.QueryFields(new SqlFieldsQuery(sql, count) {EnableDistributedJoins = true})
+                .GetAll().Distinct().Count();
+
+            Assert.AreEqual(count, res);
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
index 3abfa56..72e5f68 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
@@ -71,6 +71,7 @@
     <Compile Include="Impl\ExpressionWalker.cs" />
     <Compile Include="Package-Info.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="QueryOptions.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Apache.Ignite.Linq.nuspec" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
index e6d585c..4b536f4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
@@ -20,7 +20,6 @@ namespace Apache.Ignite.Linq
     using System.Linq;
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Configuration;
-    using Apache.Ignite.Core.Cache.Query;
     using Apache.Ignite.Linq.Impl;
 
     /// <summary>
@@ -93,7 +92,7 @@ namespace Apache.Ignite.Linq
         public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
             this ICache<TKey, TValue> cache, bool local, string tableName)
         {
-            return cache.AsCacheQueryable(local, tableName, SqlFieldsQuery.DfltPageSize, false, false);
+            return cache.AsCacheQueryable(new QueryOptions {Local = local, TableName = tableName});
         }
 
         /// <summary>
@@ -108,28 +107,14 @@ namespace Apache.Ignite.Linq
         /// <typeparam name="TKey">The type of the key.</typeparam>
         /// <typeparam name="TValue">The type of the value.</typeparam>
         /// <param name="cache">The cache.</param>
-        /// <param name="local">Local flag. When set query will be executed only on local node, so only local
-        /// entries will be returned as query result.</param>
-        /// <param name="tableName">Name of the table.
-        /// <para />
-        /// Table name is equal to short class name of a cache value.
-        /// When a cache has only one type of values, or only one <see cref="QueryEntity" /> defined,
-        /// table name will be inferred and can be omitted.</param>
-        /// <param name="pageSize">Query cursor page size. 
-        /// Defaults to <see cref="SqlFieldsQuery.DfltPageSize"/>.</param>
-        /// <param name="enableDistributedJoins">Distributed joins option, see
-        /// <see cref="SqlFieldsQuery.EnableDistributedJoins" />.</param>
-        /// <param name="enforceJoinOrder">Enforce join order flag,
-        /// see <see cref="SqlFieldsQuery.EnforceJoinOrder" />.</param>
+        /// <param name="queryOptions">The query options.</param>
         /// <returns>
         ///   <see cref="IQueryable{T}" /> instance over this cache.
         /// </returns>
         public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
-            this ICache<TKey, TValue> cache, bool local, string tableName, int pageSize,
-            bool enableDistributedJoins, bool enforceJoinOrder)
+            this ICache<TKey, TValue> cache, QueryOptions queryOptions)
         {
-            return new CacheQueryable<TKey, TValue>(cache, local, tableName, pageSize, enableDistributedJoins,
-                enforceJoinOrder);
+            return new CacheQueryable<TKey, TValue>(cache, queryOptions);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
index 7ade159..7372776 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
@@ -30,17 +30,12 @@ namespace Apache.Ignite.Linq.Impl
         /// Initializes a new instance of the <see cref="CacheQueryable{TKey, TValue}" /> class.
         /// </summary>
         /// <param name="cache">The cache.</param>
-        /// <param name="local">Local flag.</param>
-        /// <param name="tableName">Name of the table.</param>
-        /// <param name="pageSize">Size of the page.</param>
-        /// <param name="enableDistributedJoins">Distributed joins flag.</param>
-        /// <param name="enforceJoinOrder">Enforce join order flag.</param>
-        public CacheQueryable(ICache<TKey, TValue> cache, bool local, string tableName, int pageSize,
-            bool enableDistributedJoins,
-            bool enforceJoinOrder)
+        /// <param name="queryOptions">The query options.</param>
+        public CacheQueryable(ICache<TKey, TValue> cache, QueryOptions queryOptions)
             : base(new CacheFieldsQueryProvider(CacheQueryParser.Instance,
-                new CacheFieldsQueryExecutor((ICacheInternal) cache, local, pageSize, enableDistributedJoins,
-                    enforceJoinOrder), cache.Ignite, cache.GetConfiguration(), tableName, typeof(TValue)))
+                new CacheFieldsQueryExecutor((ICacheInternal) cache, queryOptions.Local, queryOptions.PageSize,
+                    queryOptions.EnableDistributedJoins, queryOptions.EnforceJoinOrder), 
+                cache.Ignite, cache.GetConfiguration(), queryOptions.TableName, typeof(TValue)))
         {
             // No-op.
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/9a808386/modules/platforms/dotnet/Apache.Ignite.Linq/QueryOptions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/QueryOptions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/QueryOptions.cs
new file mode 100644
index 0000000..4fe3ee5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/QueryOptions.cs
@@ -0,0 +1,91 @@
+\ufeff/*
+ * 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.Linq
+{
+    using System.ComponentModel;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Query;
+
+    /// <summary>
+    /// Cache query options.
+    /// </summary>
+    public class QueryOptions
+    {
+        /// <summary> Default page size. </summary>
+        public const int DefaultPageSize = SqlFieldsQuery.DfltPageSize;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="QueryOptions"/> class.
+        /// </summary>
+        public QueryOptions()
+        {
+            PageSize = DefaultPageSize;
+        }
+
+        /// <summary>
+        /// Local flag. When set query will be executed only on local node, so only local 
+        /// entries will be returned as query result.
+        /// <para />
+        /// Defaults to <c>false</c>.
+        /// </summary>
+        public bool Local { get; set; }
+
+        /// <summary>
+        /// Page size, defaults to <see cref="DefaultPageSize"/>.
+        /// </summary>
+        [DefaultValue(DefaultPageSize)]
+        public int PageSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name of the table. 
+        /// <para />
+        /// Table name is equal to short class name of a cache value.
+        /// When a cache has only one type of values, or only one <see cref="QueryEntity" /> defined,
+        /// table name will be inferred and can be omitted (null).
+        /// </summary>
+        /// <value>
+        /// The name of the table.
+        /// </value>
+        public string TableName { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether distributed joins should be enabled for this query.
+        /// <para />
+        /// When disabled, join results will only contain colocated data (joins work locally).
+        /// When enabled, joins work as expected, no matter how the data is distributed.
+        /// </summary>
+        /// <value>
+        /// <c>true</c> if enable distributed joins should be enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool EnableDistributedJoins { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether join order of tables should be enforced.
+        /// <para />
+        /// When true, query optimizer will not reorder tables in join.
+        /// <para />
+        /// It is not recommended to enable this property until you are sure that your indexes
+        /// and the query itself are correct and tuned as much as possible but
+        /// query optimizer still produces wrong join order.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if join order should be enforced; otherwise, <c>false</c>.
+        /// </value>
+        public bool EnforceJoinOrder { get; set; }
+    }
+}