IGNITE-9904: Atomic Cache operations for C++ thin
authorIgor Sapego <isapego@apache.org>
Thu, 17 Jan 2019 16:32:24 +0000 (19:32 +0300)
committerIgor Sapego <isapego@apache.org>
Thu, 17 Jan 2019 16:32:24 +0000 (19:32 +0300)
This closes #5039

modules/platforms/cpp/core/include/ignite/cache/cache.h
modules/platforms/cpp/thin-client-test/src/cache_client_test.cpp
modules/platforms/cpp/thin-client/include/ignite/impl/thin/cache/cache_client_proxy.h
modules/platforms/cpp/thin-client/include/ignite/thin/cache/cache_client.h
modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.cpp
modules/platforms/cpp/thin-client/src/impl/cache/cache_client_impl.h
modules/platforms/cpp/thin-client/src/impl/cache/cache_client_proxy.cpp
modules/platforms/cpp/thin-client/src/impl/message.h

index c230361..71aae7e 100644 (file)
@@ -531,15 +531,15 @@ namespace ignite
             }
 
             /**
-             * Atomically replaces the value for a given key if and only if there is
-             * a value currently mapped by the key.
+             * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+             * the key.
              *
              * This method should only be used on the valid instance.
              *
              * @param key Key with which the specified value is to be associated.
              * @param val Value to be associated with the specified key.
-             * @return The previous value associated with the specified key, or
-             *     null if there was no mapping for the key.
+             * @return The previous value associated with the specified key, or null if there was no mapping for
+             *     the key.
              */
             V GetAndReplace(const K& key, const V& val)
             {
@@ -553,16 +553,16 @@ namespace ignite
             }
 
             /**
-             * Atomically replaces the value for a given key if and only if there is
-             * a value currently mapped by the key.
+             * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+             * the key.
              *
              * This method should only be used on the valid instance.
              *
              * @param key Key with which the specified value is to be associated.
              * @param val Value to be associated with the specified key.
              * @param err Error.
-             * @return The previous value associated with the specified key, or
-             *     null if there was no mapping for the key.
+             * @return The previous value associated with the specified key, or null if there was no mapping for
+             *     the key.
              */
             V GetAndReplace(const K& key, const V& val, IgniteError& err)
             {
@@ -617,8 +617,8 @@ namespace ignite
             }
 
             /**
-             * Atomically associates the specified key with the given value if it is not
-             * already associated with a value.
+             * Atomically associates the specified key with the given value if it is not already associated with
+             * a value.
              *
              * This method should only be used on the valid instance.
              *
@@ -638,8 +638,8 @@ namespace ignite
             }
 
             /**
-             * Atomically associates the specified key with the given value if it is not
-             * already associated with a value.
+             * Atomically associates the specified key with the given value if it is not already associated with
+             * a value.
              *
              * This method should only be used on the valid instance.
              *
@@ -765,8 +765,8 @@ namespace ignite
             }
 
             /**
-             * Stores given key-value pair in cache only if only if the previous value is equal to the
-             * old value passed as argument.
+             * Stores given key-value pair in cache only if the previous value is equal to the old value passed
+             * as argument.
              * 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.
@@ -788,8 +788,8 @@ namespace ignite
             }
 
             /**
-             * Stores given key-value pair in cache only if only if the previous value is equal to the
-             * old value passed as argument.
+             * Stores given key-value pair in cache only if the previous value is equal to the old value passed
+             * as argument.
              * 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.
index 4031d46..d5c7f5f 100644 (file)
@@ -1199,5 +1199,715 @@ BOOST_AUTO_TEST_CASE(CacheClientContainsKeysIterators)
     BOOST_REQUIRE(cache.ContainsKeys(check.begin(), check.end()));
 }
 
+BOOST_AUTO_TEST_CASE(CacheClientReplaceIfEqualsBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    cache.Put(key, valIn1);
+
+    BOOST_CHECK(!cache.Replace(key, valIn2, valIn2));
+
+    std::string valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(cache.Replace(key, valIn1, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientReplaceIfEqualsComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    cache.Put(key, valIn1);
+
+    BOOST_REQUIRE(!cache.Replace(key, valIn2, valIn2));
+
+    ignite::ComplexType valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    BOOST_CHECK(cache.Replace(key, valIn1, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn2.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn2.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn2.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn2.objField.f2, valOut.objField.f2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientReplaceIfEqualsComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    cache.Put(key, valIn1);
+
+    BOOST_CHECK(!cache.Replace(key, valIn2, valIn2));
+
+    int32_t valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(cache.Replace(key, valIn1, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientRemoveIfEqualsBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    cache.Put(key, valIn1);
+
+    BOOST_REQUIRE(!cache.Remove(key, valIn2));
+
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    std::string valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(cache.Remove(key, valIn1));
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientRemoveIfEqualsComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    cache.Put(key, valIn1);
+
+    BOOST_CHECK(!cache.Remove(key, valIn2));
+
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    ignite::ComplexType valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    BOOST_CHECK(cache.Remove(key, valIn1));
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientRemoveIfEqualsComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    cache.Put(key, valIn1);
+
+    BOOST_CHECK(!cache.Remove(key, valIn2));
+
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    int32_t valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(cache.Remove(key, valIn1));
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    cache.Put(key, valIn1);
+    std::string valOut = cache.GetAndPut(key, valIn2);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    ignite::ComplexType valOut;
+
+    cache.Put(key, valIn1);
+    cache.GetAndPut(key, valIn2, valOut);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn2.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn2.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn2.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn2.objField.f2, valOut.objField.f2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    cache.Put(key, valIn1);
+    int32_t valOut = cache.GetAndPut(key, valIn2);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndRemoveBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn = "Lorem ipsum";
+
+    cache.Put(key, valIn);
+    std::string valOut = cache.GetAndRemove(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn);
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndRemoveComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn;
+    valIn.i32Field = 123;
+    valIn.strField = "Test value";
+    valIn.objField.f1 = 42;
+    valIn.objField.f2 = "Inner value";
+
+    ignite::ComplexType valOut;
+
+    cache.Put(key, valIn);
+    cache.GetAndRemove(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn.objField.f2, valOut.objField.f2);
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndRemoveComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn = 123;
+
+    cache.Put(key, valIn);
+    int32_t valOut = cache.GetAndRemove(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn);
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndReplaceBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    std::string valOut;
+    cache.GetAndReplace(key, valIn1, valOut);
+
+    BOOST_CHECK(valOut.empty());
+    BOOST_CHECK(!cache.ContainsKey(key));
+
+    cache.Put(key, valIn1);
+    valOut = cache.GetAndReplace(key, valIn2);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndReplaceComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    ignite::ComplexType valOut = cache.GetAndReplace(key, valIn1);
+
+    BOOST_CHECK(!cache.ContainsKey(key));
+
+    cache.Put(key, valIn1);
+    cache.GetAndReplace(key, valIn2, valOut);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn2.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn2.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn2.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn2.objField.f2, valOut.objField.f2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndReplaceComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    int32_t valOut;
+    cache.GetAndReplace(key, valIn1, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, 0);
+    BOOST_CHECK(!cache.ContainsKey(key));
+
+    cache.Put(key, valIn1);
+    valOut = cache.GetAndReplace(key, valIn2);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientPutIfAbsentBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    BOOST_CHECK(cache.PutIfAbsent(key, valIn1));
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    std::string valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(!cache.PutIfAbsent(key, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientPutIfAbsentComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    BOOST_CHECK(cache.PutIfAbsent(key, valIn1));
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    ignite::ComplexType valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    BOOST_CHECK(!cache.PutIfAbsent(key, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientPutIfAbsentComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    BOOST_CHECK(cache.PutIfAbsent(key, valIn1));
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    int32_t valOut = cache.Get(key);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    BOOST_CHECK(!cache.PutIfAbsent(key, valIn2));
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutIfAbsentBasicKeyValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, std::string> cache = client.GetCache<int32_t, std::string>("local");
+
+    int32_t key = 42;
+    std::string valIn1 = "Lorem ipsum";
+    std::string valIn2 = "Test";
+
+    std::string valOut = cache.GetAndPutIfAbsent(key, valIn1);
+
+    BOOST_CHECK(valOut.empty());
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    cache.GetAndPutIfAbsent(key, valIn2, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutIfAbsentComplexValue)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<int32_t, ignite::ComplexType> cache = client.GetCache<int32_t, ignite::ComplexType>("local");
+
+    int32_t key = 42;
+
+    ignite::ComplexType valIn1;
+    valIn1.i32Field = 123;
+    valIn1.strField = "Test value";
+    valIn1.objField.f1 = 42;
+    valIn1.objField.f2 = "Inner value";
+
+    ignite::ComplexType valIn2;
+    valIn2.i32Field = 4234;
+    valIn2.strField = "Some";
+    valIn2.objField.f1 = 654;
+    valIn2.objField.f2 = "Lorem";
+
+    ignite::ComplexType valOut = cache.GetAndPutIfAbsent(key, valIn1);
+
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    cache.GetAndPutIfAbsent(key, valIn2, valOut);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valIn1.i32Field, valOut.i32Field);
+    BOOST_CHECK_EQUAL(valIn1.strField, valOut.strField);
+    BOOST_CHECK_EQUAL(valIn1.objField.f1, valOut.objField.f1);
+    BOOST_CHECK_EQUAL(valIn1.objField.f2, valOut.objField.f2);
+}
+
+BOOST_AUTO_TEST_CASE(CacheClientGetAndPutIfAbsentComplexKey)
+{
+    IgniteClientConfiguration cfg;
+
+    cfg.SetEndPoints("127.0.0.1:11110");
+
+    IgniteClient client = IgniteClient::Start(cfg);
+
+    cache::CacheClient<ignite::ComplexType, int32_t> cache = client.GetCache<ignite::ComplexType, int32_t>("local");
+
+    ignite::ComplexType key;
+
+    key.i32Field = 123;
+    key.strField = "Test value";
+    key.objField.f1 = 42;
+    key.objField.f2 = "Inner value";
+
+    int32_t valIn1 = 123;
+    int32_t valIn2 = 321;
+
+    int32_t valOut = cache.GetAndPutIfAbsent(key, valIn1);
+
+    BOOST_CHECK_EQUAL(valOut, 0);
+    BOOST_CHECK(cache.ContainsKey(key));
+
+    cache.GetAndPutIfAbsent(key, valIn2, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+
+    cache.Get(key, valOut);
+
+    BOOST_CHECK_EQUAL(valOut, valIn1);
+}
 
 BOOST_AUTO_TEST_SUITE_END()
index cda2fae..10f19c0 100644 (file)
@@ -173,6 +173,16 @@ namespace ignite
                     bool Remove(const WritableKey& key);
 
                     /**
+                     * Removes given key mapping from cache if one exists and value is equal to the passed in value.
+                     * If write-through is enabled, the value will be removed from store.
+                     *
+                     * @param key Key whose mapping is to be removed from cache.
+                     * @param val Value to match against currently cached value.
+                     * @return True if entry was removed, false otherwise.
+                     */
+                    bool Remove(const WritableKey& key, const Writable& val);
+
+                    /**
                      * Removes given key mappings from cache.
                      * If write-through is enabled, the value will be removed from store.
                      *
@@ -208,6 +218,79 @@ namespace ignite
                     void ClearAll(const Writable& keys);
 
                     /**
+                     * Stores given key-value pair in cache only if the previous value is equal to the old value passed
+                     * as argument.
+                     *
+                     * @param key Key to store in cache.
+                     * @param oldVal Old value to match.
+                     * @param newVal Value to be associated with the given key.
+                     * @return True if replace happened, false otherwise.
+                     */
+                    bool Replace(const WritableKey& key, const Writable& oldVal, const Writable& newVal);
+
+                    /**
+                     * Associates the specified value with the specified key in this cache, returning an existing value
+                     * if one existed.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valIn Value to be associated with the specified key.
+                     * @param valOut The value associated with the key at the start of the operation or null if none
+                     *     was associated.
+                     */
+                    void GetAndPut(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
+                     * Atomically removes the entry for a key only if currently mapped to some value.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valOut The value associated with the key at the start of the operation or null if none
+                     *     was associated.
+                     */
+                    void GetAndRemove(const WritableKey& key, Readable& valOut);
+
+                    /**
+                     * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+                     * the key.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valIn Value to be associated with the specified key.
+                     * @param valOut The value associated with the key at the start of the operation or null if none was
+                     *     associated.
+                     */
+                    void GetAndReplace(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
+                     * Atomically associates the specified key with the given value if it is not already associated with
+                     * a value.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param val Value to be associated with the specified key.
+                     * @return True if a value was set.
+                     */
+                    bool PutIfAbsent(const WritableKey& key, const Writable& val);
+
+                    /**
+                     * Stores given key-value pair in cache only if cache had no previous mapping for it.
+                     *
+                     * 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 swap storage, and consecutively, if it's not in
+                     * swap, from the underlying persistent storage.
+                     *
+                     *  If the returned value is not needed, method putxIfAbsent() should be used instead of this one to
+                     * avoid the overhead associated with returning of the previous value.
+                     *
+                     * If write-through is enabled, the stored value will be persisted to store.
+                     *
+                     * @param key Key to store in cache.
+                     * @param valIn Value to be associated with the given key.
+                     * @param valOut Previously contained value regardless of whether put happened or not (null if there
+                     *     was no previous value).
+                     */
+                    void GetAndPutIfAbsent(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
                      * Get from CacheClient.
                      * Use for testing purposes only.
                      */
index 1fcf4f5..2ae6972 100644 (file)
@@ -163,9 +163,9 @@ 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.
+                 * 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.
                  *
                  * @param begin Iterator pointing to the beginning of the key sequence.
                  * @param end Iterator pointing to the end of the key sequence.
@@ -182,9 +182,9 @@ 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.
+                 * 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.
                  *
                  * @param keys Keys.
                  * @param res Map of key-value pairs.
@@ -198,9 +198,9 @@ namespace ignite
                 /**
                  * Stores given key-value pair in cache only if there is a previous mapping for it.
                  * 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 swap storage, and consecutively, if it's not
-                 * in swap, rom the underlying persistent storage.
+                 * 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 swap storage, and consecutively, if it's not in swap, rom the
+                 * underlying persistent storage.
                  * If write-through is enabled, the stored value will be persisted to store.
                  *
                  * @param key Key to store in cache.
@@ -216,6 +216,24 @@ namespace ignite
                 }
 
                 /**
+                 * Stores given key-value pair in cache only if the previous value is equal to the old value passed
+                 * as argument.
+                 *
+                 * @param key Key to store in cache.
+                 * @param oldVal Old value to match.
+                 * @param newVal Value to be associated with the given key.
+                 * @return True if replace happened, false otherwise.
+                 */
+                bool Replace(const KeyType& key, const ValueType& oldVal, const ValueType& newVal)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrOldVal(oldVal);
+                    impl::thin::WritableImpl<ValueType> wrNewVal(newVal);
+
+                    return proxy.Replace(wrKey, wrOldVal, wrNewVal);
+                }
+
+                /**
                  * Check if the cache contains a value for the specified key.
                  *
                  * @param key Key whose presence in this cache is to be tested.
@@ -270,12 +288,12 @@ namespace ignite
                 }
 
                 /**
-                 * 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
-                 * storage, and consecutively, if it's not in swap, from the underlying persistent storage.
-                 * If the returned value is not needed, method removex() should always be used instead of this
-                 * one to avoid the overhead associated with returning of the previous value.
+                 * 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 storage, and
+                 * consecutively, if it's not in swap, from the underlying persistent storage.
+                 * If the returned value is not needed, method removex() should always be used instead of this one
+                 * to avoid the overhead associated with returning of the previous value.
                  * If write-through is enabled, the value will be removed from store.
                  *
                  * @param key Key whose mapping is to be removed from cache.
@@ -289,6 +307,22 @@ namespace ignite
                 }
 
                 /**
+                 * Removes given key mapping from cache if one exists and value is equal to the passed in value.
+                 * If write-through is enabled, the value will be removed from store.
+                 *
+                 * @param key Key whose mapping is to be removed from cache.
+                 * @param val Value to match against currently cached value.
+                 * @return True if entry was removed, false otherwise.
+                 */
+                bool Remove(const KeyType& key, const ValueType& val)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrVal(val);
+
+                    return proxy.Remove(wrKey, wrVal);
+                }
+
+                /**
                  * Removes given key mappings from cache.
                  * If write-through is enabled, the value will be removed from store.
                  *
@@ -374,6 +408,181 @@ namespace ignite
                 }
 
                 /**
+                 * Associates the specified value with the specified key in this cache, returning an existing value if
+                 * one existed.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param valIn Value to be associated with the specified key.
+                 * @param valOut The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                void GetAndPut(const KeyType& key, const ValueType& valIn, ValueType& valOut)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrValIn(valIn);
+                    impl::thin::ReadableImpl<ValueType> rdValOut(valOut);
+
+                    proxy.GetAndPut(wrKey, wrValIn, rdValOut);
+                }
+
+                /**
+                 * Associates the specified value with the specified key in this cache, returning an existing value if
+                 * one existed.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param valIn Value to be associated with the specified key.
+                 * @return The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                ValueType GetAndPut(const KeyType& key, const ValueType& valIn)
+                {
+                    ValueType valOut;
+
+                    GetAndPut(key, valIn, valOut);
+
+                    return valOut;
+                }
+
+                /**
+                 * Atomically removes the entry for a key only if currently mapped to some value.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param valOut The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                void GetAndRemove(const KeyType& key, ValueType& valOut)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::ReadableImpl<ValueType> rdValOut(valOut);
+
+                    proxy.GetAndRemove(wrKey, rdValOut);
+                }
+
+                /**
+                 * Atomically removes the entry for a key only if currently mapped to some value.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @return The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                ValueType GetAndRemove(const KeyType& key)
+                {
+                    ValueType valOut;
+
+                    GetAndRemove(key, valOut);
+
+                    return valOut;
+                }
+
+                /**
+                 * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+                 * the key.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param valIn Value to be associated with the specified key.
+                 * @param valOut The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                void GetAndReplace(const KeyType& key, const ValueType& valIn, ValueType& valOut)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrValIn(valIn);
+                    impl::thin::ReadableImpl<ValueType> rdValOut(valOut);
+
+                    proxy.GetAndReplace(wrKey, wrValIn, rdValOut);
+                }
+
+                /**
+                 * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+                 * the key.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param valIn Value to be associated with the specified key.
+                 * @return The value associated with the key at the start of the operation or null if none was
+                 *     associated.
+                 */
+                ValueType GetAndReplace(const KeyType& key, const ValueType& valIn)
+                {
+                    ValueType valOut;
+
+                    GetAndReplace(key, valIn, valOut);
+
+                    return valOut;
+                }
+
+                /**
+                 * Atomically associates the specified key with the given value if it is not already associated with
+                 * a value.
+                 *
+                 * @param key Key with which the specified value is to be associated.
+                 * @param val Value to be associated with the specified key.
+                 * @return True if a value was set.
+                 */
+                bool PutIfAbsent(const KeyType& key, const ValueType& val)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrValIn(val);
+
+                    return proxy.PutIfAbsent(wrKey, wrValIn);
+                }
+
+                /**
+                 * Stores given key-value pair in cache only if cache had no previous mapping for it.
+                 *
+                 * 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 swap storage, and consecutively, if it's not in swap, from
+                 * the underlying persistent storage.
+                 *
+                 *  If the returned value is not needed, method putxIfAbsent() should be used instead of this one to
+                 * avoid the overhead associated with returning of the previous value.
+                 *
+                 * If write-through is enabled, the stored value will be persisted to store.
+                 *
+                 * @param key Key to store in cache.
+                 * @param valIn Value to be associated with the given key.
+                 * @param valOut Previously contained value regardless of whether put happened or not (null if there was
+                 *     no previous value).
+                 */
+                void GetAndPutIfAbsent(const KeyType& key, const ValueType& valIn, ValueType& valOut)
+                {
+                    impl::thin::WritableKeyImpl<KeyType> wrKey(key);
+                    impl::thin::WritableImpl<ValueType> wrValIn(valIn);
+                    impl::thin::ReadableImpl<ValueType> rdValOut(valOut);
+
+                    proxy.GetAndPutIfAbsent(wrKey, wrValIn, rdValOut);
+                }
+
+                /**
+                 * Stores given key-value pair in cache only if cache had no previous mapping for it.
+                 *
+                 * 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 swap storage, and consecutively, if it's not in swap, from
+                 * the underlying persistent storage.
+                 *
+                 *  If the returned value is not needed, method putxIfAbsent() should be used instead of this one to
+                 * avoid the overhead associated with returning of the previous value.
+                 *
+                 * If write-through is enabled, the stored value will be persisted to store.
+                 *
+                 * @param key Key to store in cache.
+                 * @param valIn Value to be associated with the given key.
+                 * @return Previously contained value regardless of whether put happened or not (null if there was no
+                 *     previous value).
+                 */
+                ValueType GetAndPutIfAbsent(const KeyType& key, const ValueType& valIn)
+                {
+                    ValueType valOut;
+
+                    GetAndPutIfAbsent(key, valIn, valOut);
+
+                    return valOut;
+                }
+
+                /**
                  * Refresh affinity mapping.
                  *
                  * Retrieves affinity mapping information from remote server. This information uses to send data
index 78d0e13..b0f3827 100644 (file)
@@ -77,7 +77,7 @@ namespace ignite
 
                 void CacheClientImpl::Put(const WritableKey& key, const Writable& value)
                 {
-                    CacheKeyValueRequest<RequestType::CACHE_PUT> req(id, binary, key, value);
+                    Cache2ValueRequest<RequestType::CACHE_PUT> req(id, binary, key, value);
                     Response rsp;
 
                     SyncCacheKeyMessage(key, req, rsp);
@@ -109,7 +109,7 @@ namespace ignite
 
                 bool CacheClientImpl::Replace(const WritableKey& key, const Writable& value)
                 {
-                    CacheKeyValueRequest<RequestType::CACHE_REPLACE> req(id, binary, key, value);
+                    Cache2ValueRequest<RequestType::CACHE_REPLACE> req(id, binary, key, value);
                     BoolResponse rsp;
 
                     SyncCacheKeyMessage(key, req, rsp);
@@ -152,7 +152,17 @@ namespace ignite
                     CacheValueRequest<RequestType::CACHE_REMOVE_KEY> req(id, binary, key);
                     BoolResponse rsp;
 
-                    SyncMessage(req, rsp);
+                    SyncCacheKeyMessage(key, req, rsp);
+
+                    return rsp.GetValue();
+                }
+
+                bool CacheClientImpl::Remove(const WritableKey& key, const Writable& val)
+                {
+                    Cache2ValueRequest<RequestType::CACHE_REMOVE_IF_EQUALS> req(id, binary, key, val);
+                    BoolResponse rsp;
+
+                    SyncCacheKeyMessage(key, req, rsp);
 
                     return rsp.GetValue();
                 }
@@ -178,7 +188,7 @@ namespace ignite
                     CacheValueRequest<RequestType::CACHE_CLEAR_KEY> req(id, binary, key);
                     Response rsp;
 
-                    SyncMessage(req, rsp);
+                    SyncCacheKeyMessage(key, req, rsp);
                 }
 
                 void CacheClientImpl::Clear()
@@ -205,6 +215,58 @@ namespace ignite
                     SyncCacheKeyMessage(key, req, rsp);
                 }
 
+                bool CacheClientImpl::Replace(const WritableKey& key, const Writable& oldVal, const Writable& newVal)
+                {
+                    Cache3ValueRequest<RequestType::CACHE_REPLACE_IF_EQUALS> req(id, binary, key, oldVal, newVal);
+                    BoolResponse rsp;
+
+                    SyncCacheKeyMessage(key, req, rsp);
+
+                    return rsp.GetValue();
+                }
+
+                void CacheClientImpl::GetAndPut(const WritableKey& key, const Writable& valIn, Readable& valOut)
+                {
+                    Cache2ValueRequest<RequestType::CACHE_GET_AND_PUT> req(id, binary, key, valIn);
+                    CacheValueResponse rsp(valOut);
+
+                    SyncCacheKeyMessage(key, req, rsp);
+                }
+
+                void CacheClientImpl::GetAndRemove(const WritableKey& key, Readable& valOut)
+                {
+                    CacheValueRequest<RequestType::CACHE_GET_AND_REMOVE> req(id, binary, key);
+                    CacheValueResponse rsp(valOut);
+
+                    SyncCacheKeyMessage(key, req, rsp);
+                }
+
+                void CacheClientImpl::GetAndReplace(const WritableKey& key, const Writable& valIn, Readable& valOut)
+                {
+                    Cache2ValueRequest<RequestType::CACHE_GET_AND_REPLACE> req(id, binary, key, valIn);
+                    CacheValueResponse rsp(valOut);
+
+                    SyncCacheKeyMessage(key, req, rsp);
+                }
+
+                bool CacheClientImpl::PutIfAbsent(const WritableKey& key, const Writable& val)
+                {
+                    Cache2ValueRequest<RequestType::CACHE_PUT_IF_ABSENT> req(id, binary, key, val);
+                    BoolResponse rsp;
+
+                    SyncCacheKeyMessage(key, req, rsp);
+
+                    return rsp.GetValue();
+                }
+
+                void CacheClientImpl::GetAndPutIfAbsent(const WritableKey& key, const Writable& valIn, Readable& valOut)
+                {
+                    Cache2ValueRequest<RequestType::CACHE_GET_AND_PUT_IF_ABSENT> req(id, binary, key, valIn);
+                    CacheValueResponse rsp(valOut);
+
+                    SyncCacheKeyMessage(key, req, rsp);
+                }
+
                 void CacheClientImpl::RefreshAffinityMapping()
                 {
                     router.Get()->RefreshAffinityMapping(id, binary);
index f9555a2..eeb0113 100644 (file)
@@ -156,6 +156,16 @@ namespace ignite
                     bool Remove(const WritableKey& key);
 
                     /**
+                     * Removes given key mapping from cache if one exists and value is equal to the passed in value.
+                     * If write-through is enabled, the value will be removed from store.
+                     *
+                     * @param key Key whose mapping is to be removed from cache.
+                     * @param val Value to match against currently cached value.
+                     * @return True if entry was removed, false otherwise.
+                     */
+                    bool Remove(const WritableKey& key, const Writable& val);
+
+                    /**
                      * Removes given key mappings from cache.
                      * If write-through is enabled, the value will be removed from store.
                      *
@@ -203,6 +213,79 @@ namespace ignite
                     void LocalPeek(const WritableKey& key, Readable& value);
 
                     /**
+                     * Stores given key-value pair in cache only if the previous value is equal to the old value passed
+                     * as argument.
+                     *
+                     * @param key Key to store in cache.
+                     * @param oldVal Old value to match.
+                     * @param newVal Value to be associated with the given key.
+                     * @return True if replace happened, false otherwise.
+                     */
+                    bool Replace(const WritableKey& key, const Writable& oldVal, const Writable& newVal);
+
+                    /**
+                     * Associates the specified value with the specified key in this cache, returning an existing value
+                     * if one existed.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valIn Value to be associated with the specified key.
+                     * @param valOut The value associated with the key at the start of the operation or null if none
+                     *     was associated.
+                     */
+                    void GetAndPut(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
+                     * Atomically removes the entry for a key only if currently mapped to some value.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valOut The value associated with the key at the start of the operation or null if none
+                     *     was associated.
+                     */
+                    void GetAndRemove(const WritableKey& key, Readable& valOut);
+
+                    /**
+                     * Atomically replaces the value for a given key if and only if there is a value currently mapped by
+                     * the key.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param valIn Value to be associated with the specified key.
+                     * @param valOut The value associated with the key at the start of the operation or null if none was
+                     *     associated.
+                     */
+                    void GetAndReplace(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
+                     * Atomically associates the specified key with the given value if it is not already associated with
+                     * a value.
+                     *
+                     * @param key Key with which the specified value is to be associated.
+                     * @param val Value to be associated with the specified key.
+                     * @return True if a value was set.
+                     */
+                    bool PutIfAbsent(const WritableKey& key, const Writable& val);
+
+                    /**
+                     * Stores given key-value pair in cache only if cache had no previous mapping for it.
+                     *
+                     * 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 swap storage, and consecutively, if it's not in
+                     * swap, from the underlying persistent storage.
+                     *
+                     *  If the returned value is not needed, method putxIfAbsent() should be used instead of this one to
+                     * avoid the overhead associated with returning of the previous value.
+                     *
+                     * If write-through is enabled, the stored value will be persisted to store.
+                     *
+                     * @param key Key to store in cache.
+                     * @param valIn Value to be associated with the given key.
+                     * @param valOut Previously contained value regardless of whether put happened or not (null if there
+                     *     was no previous value).
+                     */
+                    void GetAndPutIfAbsent(const WritableKey& key, const Writable& valIn, Readable& valOut);
+
+                    /**
                      * Update cache partitions info.
                      */
                     void RefreshAffinityMapping();
index 3d37255..266d8d4 100644 (file)
@@ -101,6 +101,11 @@ namespace ignite
                     return GetCacheImpl(impl).Remove(key);
                 }
 
+                bool CacheClientProxy::Remove(const WritableKey& key, const Writable& val)
+                {
+                    return GetCacheImpl(impl).Remove(key, val);
+                }
+
                 void CacheClientProxy::RemoveAll(const Writable & keys)
                 {
                     return GetCacheImpl(impl).RemoveAll(keys);
@@ -125,6 +130,37 @@ namespace ignite
                 {
                     GetCacheImpl(impl).ClearAll(keys);
                 }
+
+                bool CacheClientProxy::Replace(const WritableKey& key, const Writable& oldVal, const Writable& newVal)
+                {
+                    return GetCacheImpl(impl).Replace(key, oldVal, newVal);
+                }
+
+                void CacheClientProxy::GetAndPut(const WritableKey& key, const Writable& valIn, Readable& valOut)
+                {
+                    GetCacheImpl(impl).GetAndPut(key, valIn, valOut);
+                }
+
+                void CacheClientProxy::GetAndRemove(const WritableKey& key, Readable& valOut)
+                {
+                    GetCacheImpl(impl).GetAndRemove(key, valOut);
+                }
+
+                void CacheClientProxy::GetAndReplace(const WritableKey& key, const Writable& valIn, Readable& valOut)
+                {
+                    GetCacheImpl(impl).GetAndReplace(key, valIn, valOut);
+                }
+
+                bool CacheClientProxy::PutIfAbsent(const WritableKey& key, const Writable& val)
+                {
+                    return GetCacheImpl(impl).PutIfAbsent(key, val);
+                }
+
+                void CacheClientProxy::GetAndPutIfAbsent(const WritableKey& key, const Writable& valIn,
+                    Readable& valOut)
+                {
+                    GetCacheImpl(impl).GetAndPutIfAbsent(key, valIn, valOut);
+                }
             }
         }
     }
index 2d0df6f..1835991 100644 (file)
@@ -423,10 +423,10 @@ namespace ignite
             };
 
             /**
-             * Cache key value request.
+             * Cache 2 value request.
              */
             template<int32_t OpCode>
-            class CacheKeyValueRequest : public CacheValueRequest<OpCode>
+            class Cache2ValueRequest : public CacheRequest<OpCode>
             {
             public:
                 /**
@@ -434,12 +434,13 @@ namespace ignite
                  *
                  * @param cacheId Cache ID.
                  * @param binary Binary cache flag.
-                 * @param key Key.
-                 * @param value Value.
+                 * @param val1 Value 1.
+                 * @param val2 Value 2.
                  */
-                CacheKeyValueRequest(int32_t cacheId, bool binary, const Writable& key, const Writable& value) :
-                    CacheValueRequest<OpCode>(cacheId, binary, key),
-                    value(value)
+                Cache2ValueRequest(int32_t cacheId, bool binary, const Writable& val1, const Writable& val2) :
+                    CacheRequest<OpCode>(cacheId, binary),
+                    val1(val1),
+                    val2(val2)
                 {
                     // No-op.
                 }
@@ -447,7 +448,7 @@ namespace ignite
                 /**
                  * Destructor.
                  */
-                virtual ~CacheKeyValueRequest()
+                virtual ~Cache2ValueRequest()
                 {
                     // No-op.
                 }
@@ -459,14 +460,77 @@ namespace ignite
                  */
                 virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const
                 {
-                    CacheValueRequest<OpCode>::Write(writer, ver);
+                    CacheRequest<OpCode>::Write(writer, ver);
 
-                    value.Write(writer);
+                    val1.Write(writer);
+                    val2.Write(writer);
                 }
 
             private:
-                /** Value. */
-                const Writable& value;
+                /** Value 1. */
+                const Writable& val1;
+
+                /** Value 2. */
+                const Writable& val2;
+            };
+
+            /**
+             * Cache 3 value request.
+             */
+            template<int32_t OpCode>
+            class Cache3ValueRequest : public CacheRequest<OpCode>
+            {
+            public:
+                /**
+                 * Constructor.
+                 *
+                 * @param cacheId Cache ID.
+                 * @param binary Binary cache flag.
+                 * @param val1 Value 1.
+                 * @param val2 Value 2.
+                 * @param val3 Value 3.
+                 */
+                Cache3ValueRequest(int32_t cacheId, bool binary, const Writable& val1, const Writable& val2,
+                    const Writable& val3) :
+                    CacheRequest<OpCode>(cacheId, binary),
+                    val1(val1),
+                    val2(val2),
+                    val3(val3)
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Destructor.
+                 */
+                virtual ~Cache3ValueRequest()
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Write request using provided writer.
+                 * @param writer Writer.
+                 * @param ver Version.
+                 */
+                virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const
+                {
+                    CacheRequest<OpCode>::Write(writer, ver);
+
+                    val1.Write(writer);
+                    val2.Write(writer);
+                    val3.Write(writer);
+                }
+
+            private:
+                /** Value 1. */
+                const Writable& val1;
+
+                /** Value 2. */
+                const Writable& val2;
+
+                /** Value 3. */
+                const Writable& val3;
             };
 
             /**