int main(int argc, char** argv) { ConfigurationBuilder nearCacheBuilder; nearCacheBuilder.protocolVersion(argc > 1 ? argv[1] : Configuration::PROTOCOL_VERSION_24); nearCacheBuilder.addServer().host(argc > 2 ? argv[2] : "127.0.0.1").port(argc > 3 ? atoi(argv[3]) : 11222); nearCacheBuilder.balancingStrategyProducer(nullptr); nearCacheBuilder.nearCache().mode(NearCacheMode::INVALIDATED).maxEntries(10); RemoteCacheManager nearCacheManager(nearCacheBuilder.build(), false); JBasicMarshaller<std::string> *km = new JBasicMarshaller<std::string>(); JBasicMarshaller<std::string> *vm = new JBasicMarshaller<std::string>(); try { nearCacheManager.start(); RemoteCache<std::string, std::string> nearCache = nearCacheManager.getCache<std::string, std::string>(km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy); nearCache.clear(); // Read stats to do some checks on hits and miss counter std::map<std::string,std::string> statsBegin= nearCache.stats(); auto hitsBegin = std::stoi(statsBegin["hits"]); auto missesBegin = std::stoi(statsBegin["misses"]); // Only the first get goes to the remote cache and miss the value // then all the gets are resolved nearly nearCache.get("key1"); nearCache.put("key1", "value1"); std::string *rest = nearCache.get("key1"); std::cout << "Got result from near cache:" << ((rest) ? *rest : "null") << std::endl; delete rest; rest = nearCache.get("key1"); delete rest; std::map<std::string,std::string> stats1= nearCache.stats(); auto hits1 = std::stoi(stats1["hits"]); auto misses1 = std::stoi(stats1["misses"]); std::cout << "Remote misses is: " << misses1-missesBegin << "" << std::endl; std::cout << "Remote hits is: " << hits1-hitsBegin << "" << std::endl; for(int i=2; i <= 11; i++) { // fill cache with 10 more entries (11 in total) nearCache.put("key"+std::to_string(i),std::to_string(i)); } // now key1 one should not be near rest = nearCache.get("key1"); // remote get. Stored near (this delete key2 nearly) delete rest; rest = nearCache.get("key2"); // remote get. Stored near (this delete key3 nearly) delete rest; rest = nearCache.get("key1"); // near delete rest; std::map<std::string,std::string> statsEnd= nearCache.stats(); auto hitsEnd = std::stoi(statsEnd["hits"]); auto missesEnd = std::stoi(statsEnd["misses"]); std::cout << "Remote misses is: " << missesEnd-missesBegin << "" << std::endl; std::cout << "Remote hits is: " << hitsEnd-hitsBegin << "" << std::endl; } catch (Exception &e) { } try { nearCacheManager.stop(); } catch (Exception &e) { } }
int basicTest(RemoteCacheManager &cacheManager, RemoteCache<K,V> &cache) { std::cout << "HotRod C++ Library version " << cache.getVersion() << std::endl; std::cout << "Protocol " << cache.getProtocolVersion() << std::endl; std::string k1("key13"); std::string k2("key14"); std::string v1("boron"); std::string v2("chlorine"); cache.clear(); // put cache.put(k1, v1); std::unique_ptr<std::string> rv(cache.get(k1)); assert_not_null("get returned null!", __LINE__, rv); if (rv->compare(v1)) { std::cerr << "get/put fail for " << k1 << " got " << *rv << " expected " << v1 << std::endl; return 1; } cache.put(k2, v2); std::unique_ptr<std::string> rv2(cache.get(k2)); assert_not_null("get returned null!", __LINE__, rv2); if (rv2->compare(v2)) { std::cerr << "get/put fail for " << k2 << " got " << *rv2 << " expected " << v2 << std::endl; return 1; } std::unique_ptr<std::string> badValue(cache.get(std::string("no such key in the cache"))); if (badValue.get()) { std::cout << "non-existent key failure, got " << *badValue << std::endl; return 1; } std::cout << "PASS: simple get/put" << std::endl; { std::string k3("rolling"); std::string v3("stones"); std::string v4("beatles"); // putIfAbsent cache.putIfAbsent(k3, v3); std::unique_ptr<std::string> rv3(cache.get(k3)); assert_not_null("get returned null!", __LINE__, rv3); if (rv3->compare(v3)) { std::cerr << "putIfAbsent fail for " << k3 << " got " << *rv3 << " expected " << v3 << std::endl; return 1; } cache.putIfAbsent(k3, v4); std::unique_ptr<std::string> rv4(cache.get(k3)); assert_not_null("get returned null!", __LINE__, rv4); if (rv4->compare(v3)) { std::cerr << "putIfAbsent fail for " << k3 << " got " << *rv4 << " expected " << v3 << std::endl; return 1; } std::cout << "PASS: simple putIfAbsent" << std::endl; } { std::string k3("rolling"); std::string v3("stones"); std::string v4("beatles"); // putIfAbsent cache.putIfAbsent(k3, v3); std::unique_ptr<std::string> rv3(cache.get(k3)); assert_not_null("get returned null!", __LINE__, rv3); if (rv3->compare(v3)) { std::cerr << "putIfAbsent fail for " << k3 << " got " << *rv3 << " expected " << v3 << std::endl; return 1; } std::unique_ptr<std::string> rv4(cache.withFlags(FORCE_RETURN_VALUE).putIfAbsent(k3, v4)); assert_not_null("get returned null!", __LINE__, rv4); if (rv4->compare(v3)) { std::cerr << "putIfAbsent fail for " << k3 << " got " << *rv4 << " expected " << v3 << std::endl; return 1; } std::cout << "PASS: simple putIfAbsent with force return value" << std::endl; } std::string k3("rolling"); std::string v3("stones"); std::string v4("beatles"); cache.put(k3, v3, 10, SECONDS); // getWithMetadata std::pair<std::shared_ptr<std::string>, MetadataValue> rv5 = cache.getWithMetadata(k3); if (!rv5.first.get() || rv5.second.lifespan != 10) { std::cerr << "getWithMetadata with mortal entry fail for " << k3 << " not found" << std::endl; return 1; } std::cout << "PASS: simple getWithMetadata with mortal entry" << std::endl; cache.put(k3, v3); // getWithMetadata rv5 = cache.getWithMetadata(k3); if (!rv5.first.get() || rv5.second.lifespan >= 0 || rv5.second.created >= 0 || rv5.second.maxIdle >= 0 || rv5.second.lastUsed >= 0) { std::cerr << "getWithMetadata with immortal entry fail for " << k3 << std::endl; return 1; } std::cout << "PASS: simple getWithMetadata with immortal entry" << std::endl; // getWithVersion std::pair<std::shared_ptr<std::string>, VersionedValue> rv5a = cache.getWithVersion(k3); if (!rv5a.first.get()) { std::cerr << "getWithVersion fail for " << k3 << " not found" << std::endl; return 1; } std::cout << "PASS: simple getWithVersion" << std::endl; // replaceWithVersion cache.replaceWithVersion(k3, v4, rv5.second.version); std::unique_ptr<std::string> rv6(cache.get(k3)); assert_not_null("get returned null!", __LINE__, rv6); if (rv6->compare(v4)) { std::cerr << "replaceWithVersion fail for " << k3 << " got " << *rv6 << " expected " << v4 << std::endl; return 1; } cache.replaceWithVersion(k3, v3, rv5.second.version); std::unique_ptr<std::string> rv7(cache.get(k3)); assert_not_null("get returned null!", __LINE__, rv7); if (rv7->compare(v4)) { std::cerr << "replaceWithVersion fail for " << k3 << " got " << *rv7 << " expected " << v4 << std::endl; return 1; } std::cout << "PASS: simple replaceWithVersion" << std::endl; // size uint64_t size = cache.size(); if (size != 3) { std::cerr << "size fail got " << size << " expected 3 " << std::endl; return 1; } std::cout << "PASS: simple size" << std::endl; // stats const std::map<std::string,std::string>& stats = cache.stats(); if (stats.empty()) { std::cerr << "stats fail with empty map" << std::endl; return 1; } std::cout << " stats result is:" << std::endl; for(std::map<std::string,std::string>::const_iterator i=stats.begin(); i!=stats.end(); i++) { std::cout << " key: " << i->first << ", value: " << i->second << std::endl; } std::cout << "PASS: simple stats" << std::endl; // clear cache.clear(); uint64_t size2 = cache.size(); if (size2 != 0) { std::cerr << "clear fail cache has size " << size2 << " expected 0 " << std::endl; return 1; } std::cout << "PASS: simple clear" << std::endl; std::string k4("real"); std::string v5("madrid"); std::string v6("barcelona"); // put with FORCE_RETURN_VALUE flag std::unique_ptr<std::string> rv8(cache.withFlags(FORCE_RETURN_VALUE).put(k4,v5)); if (rv8.get()) { std::cerr << "put with FORCE_RETURN_FLAG fail for " << k4 << " got " << *rv8 << " expected null pointer" << std::endl; return 1; } std::unique_ptr<std::string> rv9(cache.withFlags(FORCE_RETURN_VALUE).put(k4,v6)); assert_not_null("get returned null!", __LINE__, rv9); if (rv9->compare(v5)) { std::cerr << "put with FORCE_RETURN_FLAG fail for " << k4 << " got " << *rv9 << " expected " << v5 << std::endl; return 1; } std::cout << "PASS: simple put with FORCE_RETURN_FLAG" << std::endl; // keySet std::set<std::shared_ptr<std::string> > keySet = cache.keySet(); if (keySet.size()!=1) { std::cerr << "keySet fail got " << keySet.size() << " entries expected 1" << std::endl; return 1; } std::cout << " keySet result is:" << std::endl; for(std::set<std::shared_ptr<std::string> >::const_iterator i=keySet.begin(); i!=keySet.end(); i++) { std::cout << " key: " << *i->get() << std::endl; } std::cout << "PASS: simple keySet" << std::endl; // getBulk std::map<std::shared_ptr<std::string>,std::shared_ptr<std::string> > map = cache.getBulk(); if (map.size()!=1) { std::cerr << "getBulk fail got" << map.size() << " entries expected 1" << std::endl; return 1; } std::cout << " getBulk result is:" << std::endl; for(std::map<std::shared_ptr<std::string>,std::shared_ptr<std::string> >::const_iterator i=map.begin(); i!=map.end(); i++) { std::cout << " key: " << *i->first.get() << ", value: " << *i->second.get() << std::endl; } std::cout << "PASS: simple getBulk" << std::endl; // replace cache.replace(k4,v5); std::unique_ptr<std::string> rv10(cache.get(k4)); assert_not_null("get returned null!", __LINE__, rv10); if (rv10->compare(v5)) { std::cerr << "replace fail for " << k4 << " got " << *rv10 << " expected " << v5 << std::endl; return 1; } std::cout << "PASS: simple replace" << std::endl; try { RemoteCache<std::string, std::string> namedCache = cacheManager.getCache<std::string, std::string>("namedCache", false); std::unique_ptr<std::string> namedCacheV1(namedCache.get("k1")); } catch (...) { return 1; } std::cout << "PASS: get for namedCache" << std::endl; // get non-existing cache try { RemoteCache<std::string, std::string> non_existing = cacheManager.getCache<std::string, std::string>("non-existing", false); std::cerr << "fail getCache for non-existing cache didn't throw exception" << std::endl; return 1; } catch (const HotRodClientException &ex) { std::cout << "PASS: get non-existing cache" << std::endl; } catch (const Exception &e) { std::cout << "is: " << typeid(e).name() << '\n'; std::cerr << "fail unexpected exception: " << e.what() << std::endl; return 1; } // Async test std::string ak1("asyncK1"); std::string av1("sun"); std::string ak2("asyncK2"); std::string av2("mercury"); cache.clear(); /* // Put ak1,av1 in async thread A std::future<std::string*> future_put= cache.putAsync(ak1,av1); // Get the value in this thread std::string* arv1= cache.get(ak1); if (future_put.wait_for(std::chrono::seconds(0))!=std::future_status::ready) { // get happens before put completes, arv1 must be null if (arv1) { std::cerr << "fail: expected null got value" << std::endl; return 1; } } // Now wait for put completion future_put.wait(); // All is synch now std::string* arv11= cache.get(ak1); if (!arv11 || arv11->compare(av1)) { std::cout << "fail: expected " << av1 << "got " << (arv11 ? *arv11 : "null") << std::endl; return 1; } // Read ak1 again, but in async way and test that the result is the same std::future<std::string*> future_ga= cache.getAsync(ak1); std::string* arv2= future_ga.get(); if (!arv2 || arv2->compare(av1)) { std::cerr << "fail: expected " << av1 << " got " << (arv2 ? *arv2 : "null") << std::endl; return 1; } */ bool flag=false; // Now user pass a lambda func that will be executed in the async thread after the put completion std::future<std::string*> future_put1= cache.putAsync(ak2,av2,0,0,[&] (std::string *v){flag=true; return v;}); { // If the async put is not completed flag must be false if (future_put1.wait_for(std::chrono::seconds(0))!=std::future_status::ready) { if (flag) { std::cerr << "fail: expected false got true" << std::endl; return 1; } } } // Now wait for put completion future_put1.wait(); { // The user lambda must be executed so flag must be true if (!flag) { std::cerr << "fail: expected true got false" << std::endl; return 1; } } // Same test for get flag=false; std::future<std::string*> future_get1= cache.getAsync(ak2,[&] (std::string *v){flag=true; return v;}); if (future_get1.wait_for(std::chrono::seconds(0))!=std::future_status::ready) { if (flag) { std::cerr << "fail: expected false got true" << std::endl; return 1; } } future_get1.wait(); { if (!flag) { std::cerr << "fail: expected true got false" << std::endl; return 1; } } std::string* arv3= future_get1.get(); if (!arv3 || arv3->compare(av2)) { std::cerr << "fail: expected " << av2 << " got " << (arv3 ? *arv3 : "null") << std::endl; return 1; } std::cout << "PASS: Async test" << std::endl; return 0; }