IGNITE-3585: CPP: Container-based methods now accept iterators
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d34a4d06 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d34a4d06 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d34a4d06 Branch: refs/heads/ignite-1192 Commit: d34a4d06dcab2b23cfc07544102f75f1b9d47d10 Parents: ece4928 Author: Igor Sapego <[email protected]> Authored: Mon Apr 3 16:15:58 2017 +0300 Committer: Igor Sapego <[email protected]> Committed: Mon Apr 3 16:39:01 2017 +0300 ---------------------------------------------------------------------- .../include/ignite/impl/binary/binary_utils.h | 13 +- .../cpp/core-test/include/ignite/test_utils.h | 11 + .../cpp/core-test/src/cache_query_test.cpp | 225 ++++++++++++++----- .../platforms/cpp/core-test/src/cache_test.cpp | 204 +++++++++++++++++ .../cpp/core-test/src/cluster_test.cpp | 4 +- .../cpp/core/include/ignite/cache/cache.h | 161 +++++++++++++ .../cpp/core/include/ignite/cache/cache_entry.h | 15 ++ .../include/ignite/cache/query/query_cursor.h | 28 ++- .../ignite/impl/cache/query/query_impl.h | 7 + .../cpp/core/include/ignite/impl/helpers.h | 57 +++++ .../cpp/core/include/ignite/impl/operations.h | 136 ++++++++++- .../platforms/cpp/core/project/vs/core.vcxproj | 1 + .../cpp/core/project/vs/core.vcxproj.filters | 3 + .../core/src/impl/cache/query/query_impl.cpp | 39 +++- 14 files changed, 830 insertions(+), 74 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_utils.h b/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_utils.h index 6cd90b0..268c2d8 100644 --- a/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_utils.h +++ b/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_utils.h @@ -20,14 +20,15 @@ #include <stdint.h> -#include "ignite/common/utils.h" +#include <ignite/common/utils.h> -#include "ignite/guid.h" -#include "ignite/date.h" -#include "ignite/timestamp.h" -#include "ignite/time.h" +#include <ignite/guid.h> +#include <ignite/date.h> +#include <ignite/timestamp.h> +#include <ignite/time.h> -#include "ignite/binary/binary_type.h" +#include <ignite/binary/binary_type.h> +#include <ignite/impl/binary/binary_writer_impl.h> namespace ignite { http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core-test/include/ignite/test_utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/include/ignite/test_utils.h b/modules/platforms/cpp/core-test/include/ignite/test_utils.h index 2336626..67fda95 100644 --- a/modules/platforms/cpp/core-test/include/ignite/test_utils.h +++ b/modules/platforms/cpp/core-test/include/ignite/test_utils.h @@ -58,6 +58,17 @@ namespace ignite_test * @return New node. */ ignite::Ignite StartNode(const char* cfgFile, const char* name); + + /** + * Check if the error is generic. + * + * @param err Error. + * @return True if the error is generic. + */ + inline bool IsGenericError(const ignite::IgniteError& err) + { + return err.GetCode() == ignite::IgniteError::IGNITE_ERR_GENERIC; + } } #endif // _IGNITE_CORE_TEST_TEST_UTILS \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core-test/src/cache_query_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/cache_query_test.cpp b/modules/platforms/cpp/core-test/src/cache_query_test.cpp index abb374a..871f66a 100644 --- a/modules/platforms/cpp/core-test/src/cache_query_test.cpp +++ b/modules/platforms/cpp/core-test/src/cache_query_test.cpp @@ -20,6 +20,7 @@ #endif #include <sstream> +#include <iterator> #include <boost/test/unit_test.hpp> @@ -321,16 +322,7 @@ int CountRecords(Cursor& cur) template<typename Cursor> void CheckHasNextFail(Cursor& cur) { - try - { - cur.HasNext(); - - BOOST_FAIL("Must fail."); - } - catch (IgniteError& err) - { - BOOST_REQUIRE(err.GetCode() == IgniteError::IGNITE_ERR_GENERIC); - } + BOOST_CHECK_EXCEPTION(cur.HasNext(), IgniteError, ignite_test::IsGenericError); } /** @@ -341,16 +333,7 @@ void CheckHasNextFail(Cursor& cur) template<typename Cursor> void CheckGetNextFail(Cursor& cur) { - try - { - cur.GetNext(); - - BOOST_FAIL("Must fail."); - } - catch (IgniteError& err) - { - BOOST_REQUIRE(err.GetCode() == IgniteError::IGNITE_ERR_GENERIC); - } + BOOST_CHECK_EXCEPTION(cur.GetNext(), IgniteError, ignite_test::IsGenericError); } /** @@ -360,18 +343,21 @@ void CheckGetNextFail(Cursor& cur) */ void CheckGetAllFail(QueryCursor<int, QueryPerson>& cur) { - try - { - std::vector<CacheEntry<int, QueryPerson> > res; + std::vector<CacheEntry<int, QueryPerson> > res; - cur.GetAll(res); + BOOST_CHECK_EXCEPTION(cur.GetAll(res), IgniteError, ignite_test::IsGenericError); +} - BOOST_FAIL("Must fail."); - } - catch (IgniteError& err) - { - BOOST_REQUIRE(err.GetCode() == IgniteError::IGNITE_ERR_GENERIC); - } +/** + * Ensure that iter version of GetAll() fails. + * + * @param cur Cursor. + */ +void CheckGetAllFailIter(QueryCursor<int, QueryPerson>& cur) +{ + std::vector<CacheEntry<int, QueryPerson> > res; + + BOOST_CHECK_EXCEPTION(cur.GetAll(std::back_inserter(res)), IgniteError, ignite_test::IsGenericError); } /** @@ -417,12 +403,29 @@ void CheckEmptyGetAll(QueryCursor<int, QueryPerson>& cur) } /** + * Check empty result through iter version of GetAll(). + * + * @param cur Cursor. + */ +void CheckEmptyGetAllIter(QueryCursor<int, QueryPerson>& cur) +{ + std::vector<CacheEntry<int, QueryPerson> > res; + + cur.GetAll(std::back_inserter(res)); + + BOOST_REQUIRE(res.size() == 0); + + CheckHasNextFail(cur); + CheckGetNextFail(cur); +} + +/** * Check single result through iteration. * * @param cur Cursor. - * @param key1 Key. - * @param name1 Name. - * @param age1 Age. + * @param key Key. + * @param name Name. + * @param age Age. */ void CheckSingle(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age) { @@ -472,9 +475,9 @@ void CheckSingle(QueryFieldsCursor& cur, int key, const std::string& name, int a * Check single result through GetAll(). * * @param cur Cursor. - * @param key1 Key. - * @param name1 Name. - * @param age1 Age. + * @param key Key. + * @param name Name. + * @param age Age. */ void CheckSingleGetAll(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age) { @@ -486,11 +489,40 @@ void CheckSingleGetAll(QueryCursor<int, QueryPerson>& cur, int key, const std::s CheckGetNextFail(cur); CheckGetAllFail(cur); - BOOST_REQUIRE(res.size() == 1); + BOOST_CHECK_EQUAL(res.size(), 1); - BOOST_REQUIRE(res[0].GetKey() == 1); - BOOST_REQUIRE(res[0].GetValue().GetName().compare(name) == 0); - BOOST_REQUIRE(res[0].GetValue().GetAge() == age); + BOOST_CHECK_EQUAL(res[0].GetKey(), key); + BOOST_CHECK_EQUAL(res[0].GetValue().GetName(), name); + BOOST_CHECK_EQUAL(res[0].GetValue().GetAge(), age); + + CheckHasNextFail(cur); + CheckGetNextFail(cur); + CheckGetAllFail(cur); +} + +/** + * Check single result through iter version of GetAll(). + * + * @param cur Cursor. + * @param key Key. + * @param name Name. + * @param age Age. + */ +void CheckSingleGetAllIter(QueryCursor<int, QueryPerson>& cur, int key, const std::string& name, int age) +{ + std::vector<CacheEntry<int, QueryPerson> > res; + + cur.GetAll(std::back_inserter(res)); + + CheckHasNextFail(cur); + CheckGetNextFail(cur); + CheckGetAllFail(cur); + + BOOST_CHECK_EQUAL(res.size(), 1); + + BOOST_CHECK_EQUAL(res[0].GetKey(), key); + BOOST_CHECK_EQUAL(res[0].GetValue().GetName(), name); + BOOST_CHECK_EQUAL(res[0].GetValue().GetAge(), age); CheckHasNextFail(cur); CheckGetNextFail(cur); @@ -523,18 +555,18 @@ void CheckMultiple(QueryCursor<int, QueryPerson>& cur, int key1, const std::stri if (entry.GetKey() == key1) { - BOOST_REQUIRE(entry.GetValue().GetName().compare(name1) == 0); - BOOST_REQUIRE(entry.GetValue().GetAge() == age1); + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1); } else if (entry.GetKey() == key2) { - BOOST_REQUIRE(entry.GetValue().GetName().compare(name2) == 0); - BOOST_REQUIRE(entry.GetValue().GetAge() == age2); + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2); } else BOOST_FAIL("Unexpected entry."); } - + BOOST_REQUIRE(!cur.HasNext()); CheckGetNextFail(cur); @@ -563,7 +595,7 @@ void CheckMultipleGetAll(QueryCursor<int, QueryPerson>& cur, int key1, const std CheckGetNextFail(cur); CheckGetAllFail(cur); - BOOST_REQUIRE(res.size() == 2); + BOOST_REQUIRE_EQUAL(res.size(), 2); for (int i = 0; i < 2; i++) { @@ -571,13 +603,56 @@ void CheckMultipleGetAll(QueryCursor<int, QueryPerson>& cur, int key1, const std if (entry.GetKey() == key1) { - BOOST_REQUIRE(entry.GetValue().GetName().compare(name1) == 0); - BOOST_REQUIRE(entry.GetValue().GetAge() == age1); + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1); } else if (entry.GetKey() == key2) { - BOOST_REQUIRE(entry.GetValue().GetName().compare(name2) == 0); - BOOST_REQUIRE(entry.GetValue().GetAge() == age2); + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2); + } + else + BOOST_FAIL("Unexpected entry."); + } +} + +/** + * Check multiple results through iter verion of GetAll(). + * + * @param cur Cursor. + * @param key1 Key 1. + * @param name1 Name 1. + * @param age1 Age 1. + * @param key2 Key 2. + * @param name2 Name 2. + * @param age2 Age 2. + */ +void CheckMultipleGetAllIter(QueryCursor<int, QueryPerson>& cur, int key1, const std::string& name1, + int age1, int key2, const std::string& name2, int age2) +{ + std::vector<CacheEntry<int, QueryPerson> > res; + + cur.GetAll(std::back_inserter(res)); + + CheckHasNextFail(cur); + CheckGetNextFail(cur); + CheckGetAllFail(cur); + + BOOST_REQUIRE_EQUAL(res.size(), 2); + + for (int i = 0; i < 2; i++) + { + CacheEntry<int, QueryPerson> entry = res[i]; + + if (entry.GetKey() == key1) + { + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name1); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age1); + } + else if (entry.GetKey() == key2) + { + BOOST_CHECK_EQUAL(entry.GetValue().GetName(), name2); + BOOST_CHECK_EQUAL(entry.GetValue().GetAge(), age2); } else BOOST_FAIL("Unexpected entry."); @@ -708,6 +783,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckEmptyGetAll(cursor); + cursor = cache.Query(qry); + CheckEmptyGetAllIter(cursor); + // Test simple query. cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18), MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685))); @@ -721,6 +799,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test simple distributed joins query. BOOST_CHECK(!qry.IsDistributedJoins()); qry.SetDistributedJoins(true); @@ -732,6 +813,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + qry.SetDistributedJoins(false); // Test simple local query. @@ -745,6 +829,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test query with arguments. qry.SetSql("age < ? AND name = ?"); qry.AddArgument<int>(20); @@ -756,6 +843,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test query returning multiple entries. qry = SqlQuery("QueryPerson", "age < 30"); @@ -764,6 +854,9 @@ BOOST_AUTO_TEST_CASE(TestSqlQuery) cursor = cache.Query(qry); CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20); + + cursor = cache.Query(qry); + CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20); } /** @@ -831,6 +924,9 @@ BOOST_AUTO_TEST_CASE(TestTextQuery) cursor = cache.Query(qry); CheckEmptyGetAll(cursor); + cursor = cache.Query(qry); + CheckEmptyGetAllIter(cursor); + // Test simple query. cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18), MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685))); @@ -844,6 +940,9 @@ BOOST_AUTO_TEST_CASE(TestTextQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test simple local query. qry.SetLocal(true); @@ -853,6 +952,9 @@ BOOST_AUTO_TEST_CASE(TestTextQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test query returning multiple entries. qry = TextQuery("QueryPerson", "A*"); @@ -861,6 +963,9 @@ BOOST_AUTO_TEST_CASE(TestTextQuery) cursor = cache.Query(qry); CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20); + + cursor = cache.Query(qry); + CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20); } /** @@ -880,6 +985,9 @@ BOOST_AUTO_TEST_CASE(TestScanQuery) cursor = cache.Query(qry); CheckEmptyGetAll(cursor); + cursor = cache.Query(qry); + CheckEmptyGetAllIter(cursor); + // Test simple query. cache.Put(1, QueryPerson("A1", 10, MakeDateGmt(1990, 03, 18), MakeTimestampGmt(2016, 02, 10, 17, 39, 34, 579304685))); @@ -890,6 +998,9 @@ BOOST_AUTO_TEST_CASE(TestScanQuery) cursor = cache.Query(qry); CheckSingleGetAll(cursor, 1, "A1", 10); + cursor = cache.Query(qry); + CheckSingleGetAllIter(cursor, 1, "A1", 10); + // Test query returning multiple entries. cache.Put(2, QueryPerson("A2", 20, MakeDateGmt(1989, 10, 26), MakeTimestampGmt(2016, 02, 10, 17, 39, 35, 678403201))); @@ -899,6 +1010,9 @@ BOOST_AUTO_TEST_CASE(TestScanQuery) cursor = cache.Query(qry); CheckMultipleGetAll(cursor, 1, "A1", 10, 2, "A2", 20); + + cursor = cache.Query(qry); + CheckMultipleGetAllIter(cursor, 1, "A1", 10, 2, "A2", 20); } /** @@ -1692,16 +1806,7 @@ BOOST_AUTO_TEST_CASE(TestFieldsQueryPageSingle) */ BOOST_AUTO_TEST_CASE(TestFieldsQueryPageZero) { - try - { - CheckFieldsQueryPages(0, 100, 0); - - BOOST_FAIL("Exception expected."); - } - catch (IgniteError&) - { - // Expected. - } + BOOST_CHECK_THROW(CheckFieldsQueryPages(0, 100, 0), IgniteError); } BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core-test/src/cache_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/cache_test.cpp b/modules/platforms/cpp/core-test/src/cache_test.cpp index d57b757..22ad96c 100644 --- a/modules/platforms/cpp/core-test/src/cache_test.cpp +++ b/modules/platforms/cpp/core-test/src/cache_test.cpp @@ -146,6 +146,50 @@ BOOST_AUTO_TEST_CASE(TestRemoveAllKeys) BOOST_REQUIRE(1 == size); } +BOOST_AUTO_TEST_CASE(TestRemoveAllKeysIterVector) +{ + cache::Cache<int, int> cache = Cache(); + + int size = cache.Size(cache::IGNITE_PEEK_MODE_ALL); + + BOOST_REQUIRE(0 == size); + + cache.Put(1, 1); + cache.Put(2, 2); + cache.Put(3, 3); + + int keys[] = { 1, 2, 4, 5 }; + + std::vector<int> keySet(keys, keys + 4); + + cache.RemoveAll(keySet.begin(), keySet.end()); + + size = cache.Size(cache::IGNITE_PEEK_MODE_PRIMARY); + + BOOST_REQUIRE(1 == size); +} + +BOOST_AUTO_TEST_CASE(TestRemoveAllKeysIterArray) +{ + cache::Cache<int, int> cache = Cache(); + + int size = cache.Size(cache::IGNITE_PEEK_MODE_ALL); + + BOOST_REQUIRE(0 == size); + + cache.Put(1, 1); + cache.Put(2, 2); + cache.Put(3, 3); + + int keys[] = { 1, 2, 4, 5 }; + + cache.RemoveAll(keys, keys + 4); + + size = cache.Size(cache::IGNITE_PEEK_MODE_PRIMARY); + + BOOST_REQUIRE(1 == size); +} + BOOST_AUTO_TEST_CASE(TestPut) { cache::Cache<int, int> cache = Cache(); @@ -170,6 +214,36 @@ BOOST_AUTO_TEST_CASE(TestPutAll) BOOST_REQUIRE(i + 1 == cache.Get(i)); } +BOOST_AUTO_TEST_CASE(TestPutAllIterMap) +{ + std::map<int, int> map; + + for (int i = 0; i < 100; i++) + map[i] = i + 1; + + cache::Cache<int, int> cache = Cache(); + + cache.PutAll(map.begin(), map.end()); + + for (int i = 0; i < 100; i++) + BOOST_REQUIRE(i + 1 == cache.Get(i)); +} + +BOOST_AUTO_TEST_CASE(TestPutAllIterVector) +{ + std::vector< cache::CacheEntry<int, int> > entries; + + for (int i = 0; i < 100; i++) + entries.push_back(cache::CacheEntry<int, int>(i, i + 1)); + + cache::Cache<int, int> cache = Cache(); + + cache.PutAll(entries.begin(), entries.end()); + + for (int i = 0; i < 100; i++) + BOOST_REQUIRE(i + 1 == cache.Get(i)); +} + BOOST_AUTO_TEST_CASE(TestPutIfAbsent) { cache::Cache<int, int> cache = Cache(); @@ -208,6 +282,40 @@ BOOST_AUTO_TEST_CASE(TestGetAll) BOOST_REQUIRE(i + 1 == map[i + 1]); } +BOOST_AUTO_TEST_CASE(TestGetAllIterMap) +{ + cache::Cache<int, int> cache = Cache(); + + int keys[] = { 1, 2, 3, 4, 5 }; + + for (int i = 0; i < 5; ++i) + cache.Put(keys[i], i + 1); + + std::map<int, int> map; + + cache.GetAll(keys, keys + 5, std::inserter(map, map.begin())); + + for (int i = 0; i < 5; ++i) + BOOST_REQUIRE(i + 1 == map[keys[i]]); +} + +BOOST_AUTO_TEST_CASE(TestGetAllIterArray) +{ + cache::Cache<int, int> cache = Cache(); + + int keys[] = { 1, 2, 3, 4, 5 }; + + cache::CacheEntry<int, int> res[5]; + + for (int i = 0; i < 5; ++i) + cache.Put(keys[i], i + 1); + + cache.GetAll(keys, keys + 5, res); + + for (int i = 0; i < 5; ++i) + BOOST_REQUIRE(res[i].GetKey() == res[i].GetValue()); +} + BOOST_AUTO_TEST_CASE(TestGetAndPut) { cache::Cache<int, int> cache = Cache(); @@ -284,6 +392,24 @@ BOOST_AUTO_TEST_CASE(TestContainsKeys) BOOST_REQUIRE(false == cache.ContainsKeys(keySet)); } +BOOST_AUTO_TEST_CASE(TestContainsKeysIter) +{ + cache::Cache<int, int> cache = Cache(); + + int keys[] = { 1, 2 }; + + BOOST_REQUIRE(false == cache.ContainsKeys(keys, keys + 2)); + + cache.Put(1, 1); + cache.Put(2, 2); + + BOOST_REQUIRE(true == cache.ContainsKeys(keys, keys + 2)); + + cache.Remove(1); + + BOOST_REQUIRE(false == cache.ContainsKeys(keys, keys + 2)); +} + BOOST_AUTO_TEST_CASE(TestIsEmpty) { cache::Cache<int, int> cache = Cache(); @@ -358,6 +484,44 @@ BOOST_AUTO_TEST_CASE(TestLocalClearAll) BOOST_REQUIRE(0 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_PRIMARY)); } +BOOST_AUTO_TEST_CASE(TestLocalClearAllIterList) +{ + cache::Cache<int, int> cache = Cache(); + + cache.Put(0, 3); + cache.Put(1, 3); + + int keys[] = { 0, 1 }; + + std::list<int> keySet(keys, keys + 2); + + BOOST_REQUIRE(3 == cache.LocalPeek(0, cache::IGNITE_PEEK_MODE_PRIMARY)); + BOOST_REQUIRE(3 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_PRIMARY)); + + cache.LocalClearAll(keySet.begin(), keySet.end()); + + BOOST_REQUIRE(0 == cache.LocalPeek(0, cache::IGNITE_PEEK_MODE_PRIMARY)); + BOOST_REQUIRE(0 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_PRIMARY)); +} + +BOOST_AUTO_TEST_CASE(TestLocalClearAllIterArray) +{ + cache::Cache<int, int> cache = Cache(); + + cache.Put(0, 3); + cache.Put(1, 3); + + int keys[] = { 0, 1 }; + + BOOST_REQUIRE(3 == cache.LocalPeek(0, cache::IGNITE_PEEK_MODE_PRIMARY)); + BOOST_REQUIRE(3 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_PRIMARY)); + + cache.LocalClearAll(keys, keys + 2); + + BOOST_REQUIRE(0 == cache.LocalPeek(0, cache::IGNITE_PEEK_MODE_PRIMARY)); + BOOST_REQUIRE(0 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_PRIMARY)); +} + BOOST_AUTO_TEST_CASE(TestSizes) { cache::Cache<int, int> cache = Cache(); @@ -393,6 +557,46 @@ BOOST_AUTO_TEST_CASE(TestLocalEvict) BOOST_REQUIRE(5 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); } +BOOST_AUTO_TEST_CASE(TestLocalEvictIterSet) +{ + cache::Cache<int, int> cache = Cache(); + + cache.Put(1, 5); + + BOOST_REQUIRE(5 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); + + int keys[] = { 0, 1 }; + + std::set<int> keySet(keys, keys + 2); + + cache.LocalEvict(keySet.begin(), keySet.end()); + + BOOST_REQUIRE(0 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); + + BOOST_REQUIRE(5 == cache.Get(1)); + + BOOST_REQUIRE(5 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); +} + +BOOST_AUTO_TEST_CASE(TestLocalEvictIterArray) +{ + cache::Cache<int, int> cache = Cache(); + + cache.Put(1, 5); + + BOOST_REQUIRE(5 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); + + int keys[] = { 0, 1 }; + + cache.LocalEvict(keys, keys + 2); + + BOOST_REQUIRE(0 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); + + BOOST_REQUIRE(5 == cache.Get(1)); + + BOOST_REQUIRE(5 == cache.LocalPeek(1, cache::IGNITE_PEEK_MODE_ONHEAP)); +} + BOOST_AUTO_TEST_CASE(TestBinary) { cache::Cache<int, Person> cache = grid0.GetCache<int, Person>("partitioned"); http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core-test/src/cluster_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/cluster_test.cpp b/modules/platforms/cpp/core-test/src/cluster_test.cpp index 7b206d2..c681ca2 100644 --- a/modules/platforms/cpp/core-test/src/cluster_test.cpp +++ b/modules/platforms/cpp/core-test/src/cluster_test.cpp @@ -34,7 +34,7 @@ using namespace boost::unit_test; */ struct ClusterTestSuiteFixture { - Ignite grid; + Ignite node; /* * Constructor. @@ -52,8 +52,6 @@ struct ClusterTestSuiteFixture { Ignition::StopAll(true); } - - Ignite node; }; BOOST_FIXTURE_TEST_SUITE(ClusterTestSuite, ClusterTestSuiteFixture) http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/cache/cache.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/cache/cache.h b/modules/platforms/cpp/core/include/ignite/cache/cache.h index 00d1c81..33fffc8 100644 --- a/modules/platforms/cpp/core/include/ignite/cache/cache.h +++ b/modules/platforms/cpp/core/include/ignite/cache/cache.h @@ -185,6 +185,29 @@ namespace ignite * * This method should only be used on the valid instance. * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + * @return True if cache contains mapping for all these keys. + */ + template<typename InputIter> + bool ContainsKeys(InputIter begin, InputIter end) + { + IgniteError err; + + impl::InIterOperation<K, V, InputIter> op(begin, end); + + bool res = impl.Get()->ContainsKeys(op, err); + + IgniteError::ThrowIfNeeded(err); + + return res; + } + + /** + * Check if cache contains mapping for these keys. + * + * This method should only be used on the valid instance. + * * @param keys Keys. * @param err Error. * @return True if cache contains mapping for all these keys. @@ -337,6 +360,32 @@ namespace ignite } /** + * Retrieves values mapped to the specified keys from cache. + * If some value is not present in cache, then it will be looked up from swap storage. If + * it's not present in swap, or if swap is disabled, and if read-through is allowed, value + * will be loaded from persistent store. + * This method is transactional and will enlist the entry into ongoing transaction if there is one. + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + * @param dst Output iterator. Should dereference to std::pair or CacheEntry. + */ + template<typename InIter, typename OutIter> + void GetAll(InIter begin, InIter end, OutIter dst) + { + IgniteError err; + + impl::InIterOperation<K, V, InIter> inOp(begin, end); + impl::OutMapIterOperation<K, V, OutIter> outOp(dst); + + impl.Get()->GetAll(inOp, outOp, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Associates the specified value with the specified key in the cache. * If the cache previously contained a mapping for the key, * the old value is replaced by the specified value. @@ -409,6 +458,28 @@ namespace ignite } /** + * Stores given key-value pairs in cache. + * If write-through is enabled, the stored values will be persisted to store. + * This method is transactional and will enlist the entry into ongoing transaction if there is one. + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key-value pair sequence. + * @param end Iterator pointing to the end of the key-value pair sequence. + */ + template<typename Iter> + void PutAll(Iter begin, Iter end) + { + IgniteError err; + + impl::InIterOperation<K, V, Iter> op(begin, end); + + impl.Get()->PutAll(op, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Associates the specified value with the specified key in this cache, * returning an existing value if one existed. * @@ -761,6 +832,29 @@ namespace ignite } /** + * Attempts to evict all entries associated with keys. + * + * @note Entry will be evicted only if it's not used (not + * participating in any locks or transactions). + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + */ + template<typename Iter> + void LocalEvict(Iter begin, Iter end) + { + IgniteError err; + + impl::InIterOperation<K, V, Iter> op(begin, end); + + impl.Get()->LocalEvict(op, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Clear cache. * * This method should only be used on the valid instance. @@ -853,6 +947,27 @@ namespace ignite } /** + * Clear entries from the cache and swap storage, without notifying listeners or CacheWriters. + * Entry is cleared only if it is not currently locked, and is not participating in a transaction. + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + */ + template<typename Iter> + void ClearAll(Iter begin, Iter end) + { + IgniteError err; + + impl::InIterOperation<K, V, Iter> op(begin, end); + + impl.Get()->ClearAll(op, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Clear entry from the cache and swap storage, without notifying listeners or CacheWriters. * Entry is cleared only if it is not currently locked, and is not participating in a transaction. * @@ -931,6 +1046,30 @@ namespace ignite } /** + * Clear entries from the cache and swap storage, without notifying listeners or CacheWriters. + * Entry is cleared only if it is not currently locked, and is not participating in a transaction. + * + * @note This operation is local as it merely clears entries from local cache, it does not + * remove entries from remote caches. + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + */ + template<typename Iter> + void LocalClearAll(Iter begin, Iter end) + { + IgniteError err; + + impl::InIterOperation<K, V, Iter> op(begin, end); + + impl.Get()->LocalClearAll(op, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Removes given key mapping from cache. If cache previously contained value for the given key, * then this value is returned. In case of PARTITIONED or REPLICATED caches, the value will be * loaded from the primary node, which in its turn may load the value from the disk-based swap @@ -1056,6 +1195,28 @@ namespace ignite } /** + * Removes given key mappings from cache. + * If write-through is enabled, the value will be removed from store. + * This method is transactional and will enlist the entry into ongoing transaction if there is one. + * + * This method should only be used on the valid instance. + * + * @param begin Iterator pointing to the beggining of the key sequence. + * @param end Iterator pointing to the end of the key sequence. + */ + template<typename Iter> + void RemoveAll(Iter begin, Iter end) + { + IgniteError err; + + impl::InIterOperation<K, V, Iter> op(begin, end); + + impl.Get()->RemoveAll(op, err); + + IgniteError::ThrowIfNeeded(err); + } + + /** * Removes all mappings from cache. * If write-through is enabled, the value will be removed from store. * This method is transactional and will enlist the entry into ongoing transaction if there is one. http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/cache/cache_entry.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/cache/cache_entry.h b/modules/platforms/cpp/core/include/ignite/cache/cache_entry.h index aea5182..c88f918 100644 --- a/modules/platforms/cpp/core/include/ignite/cache/cache_entry.h +++ b/modules/platforms/cpp/core/include/ignite/cache/cache_entry.h @@ -23,6 +23,7 @@ #ifndef _IGNITE_CACHE_CACHE_ENTRY #define _IGNITE_CACHE_CACHE_ENTRY +#include <utility> #include <ignite/common/common.h> namespace ignite @@ -80,6 +81,20 @@ namespace ignite } /** + * Constructor. + * + * @param p Pair. + */ + CacheEntry(const std::pair<K, V>& p) : + key(p.first), + val(p.second), + hasValue(true) + { + // No-op. + } + + + /** * Destructor. */ virtual ~CacheEntry() http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h index 61fd7ec..3f7ccce 100644 --- a/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h +++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_cursor.h @@ -186,7 +186,7 @@ namespace ignite * * This method should only be used on the valid instance. * - * @param Vector where query entries will be stored. + * @param res Vector where query entries will be stored. * * @throw IgniteError class instance in case of failure. */ @@ -205,7 +205,7 @@ namespace ignite * * This method should only be used on the valid instance. * - * @param Vector where query entries will be stored. + * @param res Vector where query entries will be stored. * @param err Used to set operation result. */ void GetAll(std::vector<CacheEntry<K, V> >& res, IgniteError& err) @@ -223,6 +223,30 @@ namespace ignite } /** + * Get all entries. + * + * This method should only be used on the valid instance. + * + * @param iter Output iterator. + */ + template<typename OutIter> + void GetAll(OutIter iter) + { + impl::cache::query::QueryCursorImpl* impl0 = impl.Get(); + + if (impl0) { + impl::OutQueryGetAllOperationIter<K, V, OutIter> outOp(iter); + + impl0->GetAll(outOp); + } + else + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Instance is not usable (did you check for error?)."); + } + } + + /** * Check if the instance is valid. * * Invalid instance can be returned if some of the previous http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h index 4083c7c..7306805 100644 --- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h +++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_impl.h @@ -85,6 +85,13 @@ namespace ignite */ void GetAll(OutputOperation& op, IgniteError& err); + /** + * Get all cursor entries. + * + * @param op Operation. + */ + void GetAll(OutputOperation& op); + private: /** Environment. */ ignite::common::concurrent::SharedPointer<impl::IgniteEnvironment> env; http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/impl/helpers.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/impl/helpers.h b/modules/platforms/cpp/core/include/ignite/impl/helpers.h new file mode 100644 index 0000000..bc9eb39 --- /dev/null +++ b/modules/platforms/cpp/core/include/ignite/impl/helpers.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef _IGNITE_IMPL_HELPERS +#define _IGNITE_IMPL_HELPERS + +#include <map> + +#include <ignite/cache/cache_entry.h> +#include <ignite/impl/binary/binary_writer_impl.h> + +namespace ignite +{ + namespace impl + { + /** + * Class-helper to properly write values of different type. + */ + template<typename K, typename V> + struct ContainerEntryWriteHelper + { + template<typename E> + static void Write(binary::BinaryWriterImpl& writer, const E& val) + { + writer.WriteTopObject(val); + } + + static void Write(binary::BinaryWriterImpl& writer, const typename std::map<K, V>::value_type& val) + { + writer.WriteTopObject(val.first); + writer.WriteTopObject(val.second); + } + + static void Write(binary::BinaryWriterImpl& writer, const ignite::cache::CacheEntry<K, V>& val) + { + writer.WriteTopObject(val.GetKey()); + writer.WriteTopObject(val.GetValue()); + } + }; + } +} + +#endif //_IGNITE_IMPL_HELPERS http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/include/ignite/impl/operations.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/impl/operations.h b/modules/platforms/cpp/core/include/ignite/impl/operations.h index fff8a86..1645fb56 100644 --- a/modules/platforms/cpp/core/include/ignite/impl/operations.h +++ b/modules/platforms/cpp/core/include/ignite/impl/operations.h @@ -28,6 +28,7 @@ #include "ignite/impl/binary/binary_reader_impl.h" #include "ignite/impl/binary/binary_writer_impl.h" #include "ignite/impl/binary/binary_utils.h" +#include "ignite/impl/helpers.h" #include "ignite/binary/binary.h" namespace ignite @@ -253,6 +254,50 @@ namespace ignite }; /** + * Input iterator operation. + */ + template<typename K, typename V, typename Iter> + class InIterOperation : public InputOperation + { + public: + /** + * Constructor. + * + * @param begin Iterator pointing to the beggining of the sequence. + * @param end Iterator pointing to the end of the key sequence. + */ + InIterOperation(Iter begin, Iter end) : + begin(begin), + end(end) + { + // No-op. + } + + virtual void ProcessInput(ignite::impl::binary::BinaryWriterImpl& writer) + { + interop::InteropOutputStream& stream = *writer.GetStream(); + int32_t sizePos = stream.Reserve(4); + + int32_t size = 0; + for (Iter it = begin; it != end; ++it) + { + ContainerEntryWriteHelper<K, V>::Write(writer, *it); + ++size; + } + + stream.WriteInt32(sizePos, size); + } + private: + /** Sequence begining. */ + Iter begin; + + /** Sequence end. */ + Iter end; + + IGNITE_NO_COPY_ASSIGNMENT(InIterOperation) + }; + + /** * Output operation. */ class OutputOperation @@ -496,7 +541,7 @@ namespace ignite val0[t1] = t2; } - val = val0; + std::swap(val, val0); } } @@ -508,7 +553,7 @@ namespace ignite /** * Get value. * - * @param Value. + * @return Value. */ std::map<T1, T2> GetResult() { @@ -540,6 +585,8 @@ namespace ignite { int32_t cnt = reader.ReadInt32(); + res.reserve(res.size() + cnt); + for (int i = 0; i < cnt; i++) { K key = reader.ReadTopObject<K>(); @@ -560,6 +607,91 @@ namespace ignite IGNITE_NO_COPY_ASSIGNMENT(OutQueryGetAllOperation) }; + + /** + * Output query GET ALL operation. + */ + template<typename K, typename V, typename Iter, typename Pair = ignite::cache::CacheEntry<K,V> > + class OutQueryGetAllOperationIter : public OutputOperation + { + public: + /** + * Constructor. + */ + OutQueryGetAllOperationIter(Iter iter) : iter(iter) + { + // No-op. + } + + virtual void ProcessOutput(binary::BinaryReaderImpl& reader) + { + int32_t cnt = reader.ReadInt32(); + + for (int32_t i = 0; i < cnt; i++) + { + K key = reader.ReadTopObject<K>(); + V val = reader.ReadTopObject<V>(); + + *iter = Pair(key, val); + ++iter; + } + } + + virtual void SetNull() + { + // No-op. + } + + private: + /** Out iter. */ + Iter iter; + + IGNITE_NO_COPY_ASSIGNMENT(OutQueryGetAllOperationIter) + }; + + /** + * Output iter operation. + */ + template<typename K, typename V, typename Iter> + class OutMapIterOperation :public OutputOperation + { + public: + /** + * Constructor. + */ + OutMapIterOperation(Iter iter) : iter(iter) + { + // No-op. + } + + virtual void ProcessOutput(binary::BinaryReaderImpl& reader) + { + bool exists = reader.GetStream()->ReadBool(); + + if (exists) + { + int32_t cnt = reader.GetStream()->ReadInt32(); + + for (int32_t i = 0; i < cnt; i++) { + K key = reader.ReadTopObject<K>(); + V val = reader.ReadTopObject<V>(); + + *iter = std::pair<K, V>(key, val); + ++iter; + } + } + } + + virtual void SetNull() + { + // No-op. + } + private: + /** Out iter. */ + Iter iter; + + IGNITE_NO_COPY_ASSIGNMENT(OutMapIterOperation) + }; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/project/vs/core.vcxproj ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/project/vs/core.vcxproj b/modules/platforms/cpp/core/project/vs/core.vcxproj index b5a95bd..5cd49f3 100644 --- a/modules/platforms/cpp/core/project/vs/core.vcxproj +++ b/modules/platforms/cpp/core/project/vs/core.vcxproj @@ -225,6 +225,7 @@ <ClInclude Include="..\..\include\ignite\impl\cache\query\query_fields_row_impl.h" /> <ClInclude Include="..\..\include\ignite\impl\cache\query\query_impl.h" /> <ClInclude Include="..\..\include\ignite\impl\cluster\cluster_group_impl.h" /> + <ClInclude Include="..\..\include\ignite\impl\helpers.h" /> <ClInclude Include="..\..\include\ignite\impl\ignite_environment.h" /> <ClInclude Include="..\..\include\ignite\impl\ignite_impl.h" /> <ClInclude Include="..\..\include\ignite\impl\handle_registry.h" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/project/vs/core.vcxproj.filters ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/project/vs/core.vcxproj.filters b/modules/platforms/cpp/core/project/vs/core.vcxproj.filters index 3b17d53..98099a9 100644 --- a/modules/platforms/cpp/core/project/vs/core.vcxproj.filters +++ b/modules/platforms/cpp/core/project/vs/core.vcxproj.filters @@ -207,6 +207,9 @@ <ClInclude Include="..\..\include\ignite\impl\bindings.h"> <Filter>Code\impl</Filter> </ClInclude> + <ClInclude Include="..\..\include\ignite\impl\helpers.h"> + <Filter>Code\impl</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Filter Include="Code"> http://git-wip-us.apache.org/repos/asf/ignite/blob/d34a4d06/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp b/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp index 018bd99..a7bf0e4 100644 --- a/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp +++ b/modules/platforms/cpp/core/src/impl/cache/query/query_impl.cpp @@ -186,12 +186,49 @@ namespace ignite InteropInputStream in(inMem.Get()); - binary::BinaryReaderImpl reader(&in); + BinaryReaderImpl reader(&in); op.ProcessOutput(reader); } } + void QueryCursorImpl::GetAll(OutputOperation& op) + { + // Check whether any of iterator methods were called. + if (iterCalled) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Cannot use GetAll() method because an iteration method was called."); + } + + // Check whether GetAll was called before. + if (getAllCalled) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Cannot use GetNext() method because GetAll() was called."); + } + + // Get data. + JniErrorInfo jniErr; + + SharedPointer<InteropMemory> inMem = env.Get()->AllocateMemory(); + + env.Get()->Context()->TargetOutStream(javaRef, OP_GET_ALL, inMem.Get()->PointerLong(), &jniErr); + + IgniteError err; + IgniteError::SetError(jniErr.code, jniErr.errCls, jniErr.errMsg, err); + + IgniteError::ThrowIfNeeded(err); + + getAllCalled = true; + + InteropInputStream in(inMem.Get()); + + BinaryReaderImpl reader(&in); + + op.ProcessOutput(reader); + } + bool QueryCursorImpl::CreateIteratorIfNeeded(IgniteError& err) { if (iterCalled)
