Giter VIP home page Giter VIP logo

cylix / cpp_redis Goto Github PK

View Code? Open in Web Editor NEW
1.2K 87.0 550.0 2.04 MB

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform - NO LONGER MAINTAINED - Please check https://github.com/cpp-redis/cpp_redis

License: MIT License

CMake 2.01% C++ 96.77% Shell 0.04% Python 1.18%
cpp cpp11 redis redis-client unix windows multi-platform asynchronous no-dependencies

cpp_redis's Introduction

Important

Please be advised that this library is no longer maintained.

For new updates, please refer to the following fork https://github.com/cpp-redis/cpp_redis

I have maintained this library for over 3 years, but I do not have enough time to provide a reliable support and continuous development for any longer.

Any existing or new issues will not be treated and I do not guarantee to merge any new pull request.

If anyone is willing to take over this project, feel free to fork this project and message me to add a link to your fork in this README.

cpp_redis Build Status Build status

cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client, with support for synchronous operations, pipelining, sentinels and high availability.

Requirement

cpp_redis has no dependency. Its only requirement is C++11.

It comes with no network module, so you are free to configure your own, or to use the default one (tacopie)

Example

cpp_redis::client

cpp_redis::client client;

client.connect();

client.set("hello", "42");
client.get("hello", [](cpp_redis::reply& reply) {
  std::cout << reply << std::endl;
});
//! also support std::future
//! std::future<cpp_redis::reply> get_reply = client.get("hello");

client.sync_commit();
//! or client.commit(); for asynchronous call

cpp_redis::client full documentation and detailed example. More about cpp_redis::reply.

cpp_redis::subscriber

cpp_redis::subscriber sub;

sub.connect();

sub.subscribe("some_chan", [](const std::string& chan, const std::string& msg) {
  std::cout << "MESSAGE " << chan << ": " << msg << std::endl;
});
sub.psubscribe("*", [](const std::string& chan, const std::string& msg) {
  std::cout << "PMESSAGE " << chan << ": " << msg << std::endl;
});

sub.commit();

cpp_redis::subscriber full documentation and detailed example.

Wiki

A Wiki is available and provides full documentation for the library as well as installation explanations.

Doxygen

A Doxygen documentation is available and provides full API documentation for the library.

License

cpp_redis is under MIT License.

Contributing

Please refer to CONTRIBUTING.md.

Special Thanks

Mike Moening for his unexpected and incredible great work aiming to port cpp_redis on Windows, provides sentinel support and high availability support!

Author

Simon Ninon

cpp_redis's People

Contributors

aardvarkk avatar cblauvelt avatar cmorse avatar costypetrisor avatar cylix avatar fengzhuye avatar fpagliughi avatar knowledge4igor avatar konijnendijk avatar krojew avatar lucasterra avatar m-harnish avatar mikesaracade avatar mugglewei avatar navossoc avatar nerdneilsfield avatar njwhite avatar panaali avatar pfultz2 avatar ppietrasa avatar rfortunatov avatar steple avatar thedrow avatar thequantumphysicist avatar tobbe303 avatar turanic avatar whoshuu avatar wujunjenny avatar yiurule avatar zodiac403 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cpp_redis's Issues

CMake issues under windows

Hello, guys :)

Thanks for your nice library!
I want to point some bugs I faced while generating VS projects from CMakeLists.txt.

  1. On this page: https://github.com/Cylix/cpp_redis/wiki/Compilation-and-installation-options you are saying:

"You can use the MSVC_RUNTIME_LIBRARY_CONFIG Cmake variable to override this setting and choose the Runtime Library of your choice (/MT, /MD, /MTd, /MDd, ...)."

As I understand, only /MT and /MD are applicable, as /MTd and /MDd will automatically apply to Debug versions accordingly. Using /MTd will cause /MTd for Release and /MTdd for Debug.

  1. After I changed MSVC_RUNTIME_LIBRARY_CONFIG to /MD I faced another problem:

This config is applied only to cpp_redis library, but not to tacopie. Since I need to link both libraries, I would prefer both of them build with the same MSVC_RUNTIME_LIBRARY_CONFIG flag.

Something like this, but with OS check, as for Linux we do not care about this flag:

IF (NOT USE_CUSTOM_TCP_CLIENT)
ExternalProject_Add("tacopie"
GIT_SUBMODULES ""
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${PROJECT_SOURCE_DIR}/deps"
CMAKE_ARGS "-DMSVC_RUNTIME_LIBRARY_CONFIG=${MSVC_RUNTIME_LIBRARY_CONFIG}"
SOURCE_DIR "${PROJECT_SOURCE_DIR}/tacopie")
ENDIF (NOT USE_CUSTOM_TCP_CLIENT)

  1. After VS projects generated, one of *.cpp files won't compile because of it's extra-large *.obj file. One additional argument should be passed to VS compiler: /bigobj.

  2. Minor one: please, mention on your Wiki page, that for correct x64 platform(which is mainstream nowadays) we need to force generator to e. g. "cmake . -G "Visual Studio 15 2017 Win64". Without forcing, user will receive projects with both x86 and x64 platform configurations, but x64 ones will be broken(wrong machine types in configurations and others).

That's it :)

smembers return

Hello,
I need to request a redis db containing sets.
I think there is a problem with smembers and its return values :

std::vector<int> el; client.smembers(key), [&] (cpp_redis::reply& reply) { std::vector<cpp_redis::reply> rep = reply.as_array(); for (auto it = rep.begin(); it != rep.end(); it++){ el.push_back(std::stoi(it->as_string())); } }); client.commit();

I get pieces of the good answer and then segfault or memory error if i use this code. But if I put a sleep(1) before (or after) client.commit(); it's ok.

So I think the problem is the client is not reading returned values as far as they're sent. I can't use a sleep(1) because of my application.

Have you ever experienced that ? Thank you for your help.

`namespace unix` conflicts with `unix` macro

I'm using gcc version 5.4.0 on Ubuntu 16.04 and getting a compiler error on io_service.cpp line 24. I believe unix is defined as a macro which is throwing the error expected identifier before numeric constant.

No reply when reconnection completed.

I tried a simple reconnection in callback of client connect:

void RedisSender::connect() {
    try {
      this->client->connect(this->host, this->port, [this](cpp_redis::redis_client&) {
        LOG(WARNING) << "Redis disconnected, reconnecting..." << endl;
        this_thread::sleep_for(chrono::seconds(1));
        if((++ this->retries) < RECONNECT_RETRIES)
            this->connect();
      });
      
      if(this->auth.length() > 0)
        this->client->auth(this->auth, [](cpp_redis::reply& reply) {
          if(string("OK").compare(reply.as_string()) != 0)
              LOG(FATAL) << "Redis client authenticated failed.";
      });
      
      this->client->select(this->db, [](cpp_redis::reply& reply) {
          if(string("OK").compare(reply.as_string()) != 0)
              LOG(FATAL) << "Redis client select db failed.";
      });
      
      LOG(INFO) << "Redis client connected to " << this->host << ":" << this->port << "/" << this->db;
      this->client->commit();
    }
    catch(exception &e) {
        LOG(ERROR) << "Redis client connected failed with " << e.what();
        this_thread::sleep_for(chrono::seconds(1));
        if((++ this->retries) < RECONNECT_RETRIES)
            this->connect();
    }
}

// and a loop for test:
void RedisSender::test(string key, string value) {
    try{
        this->client->set(key, value);    
        this->client->get(key, [](cpp_redis::reply& reply) {
            LOG(INFO) << "get hello: " << reply;
        });
        LOG(WARNING) << "test " << value;
        this->client->commit();
    }
    catch(exception &e) {
        this_thread::sleep_for(chrono::seconds(1));
        LOG(WARNING) << "failed ";
    }
}

Then I restat the redis-server, after the reconnection successfully completed, no reply such as "get hello: xx" outputs, but "set" command just work fine!
so how should I fix this issue.

blpop got a "client disconnected" at the timeout

Hello,
the following program got a "client disconnected" at the timeout of blpop.

int main(int argc, _TCHAR* argv[])
{

	bool should_exit = false;
	cpp_redis::sync_client client;
	client.connect("host", 6379, [](cpp_redis::redis_client&) {
		std::cout << "client disconnected (disconnection handler)" << std::endl;
	});
	cpp_redis::reply reply;
	std::vector<std::string> not_exists = { "NOEXISTS" };
	while (!should_exit) {
		try {
			std::cout << "Waiting..." << std::endl;
			reply = client.blpop(not_exists, 3); // At the end of timeout get a "client disconnected"
		}
		catch (...) {
			std::cout << "Stop..." << std::endl;
			should_exit = true;
		}
	}
	client.incrbyfloat("prova", 4); // Never executed, client disconnected before
	client.disconnect();
	return 0;
}

Log

[←[1;34mINFO ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:48] cpp_redis::redis_client connected
Waiting...
[←[1;34mINFO ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:69] cpp_redis::redis_client attemps to store new command in the send buffer
[←[1;34mINFO ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:72] cpp_redis::redis_client stored new command in the send buffer
[←[1;34mINFO ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:108] cpp_redis::redis_client sent pipelined commands
[←[1;31mERROR←[0;39m][cpp_redis][C:\cpp_redis\sources\builders\array_builder.cpp:48] cpp_redis::builders::array_builder receives invalid array size
[←[1;31mERROR←[0;39m][cpp_redis][C:\cpp_redis\sources\network\redis_connection.cpp:111] cpp_redis::network::redis_connection could not build reply (invalid format), disconnecting
[←[1;33mWARN ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:166] cpp_redis::redis_client has been disconnected
[←[1;34mINFO ←[0;39m][cpp_redis][C:\cpp_redis\sources\redis_client.cpp:159] cpp_redis::redis_client calls disconnection handler
Stop...
client disconnected (disconnection handler)

Thank you

Simone

exception on ubuntu 16.04 with clang++

hi,buddy. I have a problem with this library. Some exceptions occured when my program run with this library.

here is my code:

   this->redisClient.lpop("documentId",[&documentId](cpp_redis::reply& reply) {
        if (reply.is_string()){
            documentId = reply.as_string();
        }
    });
    this->redisClient.sync_commit();

The code will be execute in a loop. When the code run several times, the exception happened.

the callstack is here:

process:

std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > >, std::__cxx11::regex_traits, true>::_M_dfs(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string > > >, std::__cxx11::regex_traits, true> * this, std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string > > >, std::__cxx11::regex_traits, true>::_Match_mode __match_mode, std::__detail::_StateIdT __i) (/usr/include/c++/5/bits/regex_executor.tcc:203)
std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > >, std::__cxx11::regex_traits, true>::_M_dfs(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string > > >, std::__cxx11::regex_traits, true> * this, std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string > > >, std::__cxx11::regex_traits, true>::_Match_mode __match_mode, std::__detail::_StateIdT __i) (/usr/include/c++/5/bits/regex_executor.tcc:230)
std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > >, std::__cxx11::regex_traits
...........there are many repeat message......

process:

pthread_cond_wait@@GLIBC_2.3.2() (/build/glibc-9tT8Do/glibc-2.23/nptl/../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185)
std::condition_variable::wait(std::unique_lockstd::mutex&) (/未知源:0)
tacopie::utils::thread_pool::fetch_task() (/未知源:0)
tacopie::utils::thread_pool::run() (/未知源:0)
[Unknown/Just-In-Time compiled code] (/未知源:0)
start_thread(void * arg) (/build/glibc-9tT8Do/glibc-2.23/nptl/pthread_create.c:333)
clone() (/build/glibc-9tT8Do/glibc-2.23/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:109)

process

poll() (/build/glibc-9tT8Do/glibc-2.23/io/../sysdeps/unix/syscall-template.S:84)
tacopie::io_service::poll() (/未知源:0)
[Unknown/Just-In-Time compiled code] (/未知源:0)
start_thread(void * arg) (/build/glibc-9tT8Do/glibc-2.23/nptl/pthread_create.c:333)
clone() (/build/glibc-9tT8Do/glibc-2.23/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:109)

I have no idea how to fix it. Is there any mistake with my code or something else wrong ?

thanks!

where is zadd?

hi, Thx for your great work.
I can't find zadd command.
Does it mean that I mjust create sorted sets through text command?
Is there a plan to implement it in future?

API for sorted sets using integers for scores

In Redis, the sorted sets use double-precision floats to represent scores. In the cpp_redis API, these are exposed as integers, such as in this method:

redis_client& zremrangebyscore(const std::string& key, int min, int max, const reply_callback_t& reply_callback = nullptr);

In this case, min and max should be type double instead of int to expose the full functionality of the database server.

This is especially important since Redis is a great means to store time-series data in sorted sets for scientific and real-time applications. Those data sets typically use floating-point timestamps for sub-second precision.

This is a (minor) breaking change in the API.

Crash on free in io_service::write_fd

I'm not sure exactly what causes this yet but am seeing a callstack with the following backtrace:

*** Error in `server': free(): invalid next size (fast): 0x00000000013a6190 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x6ef45)[0x7efd60bdff45]
/lib/x86_64-linux-gnu/libc.so.6(+0x746b6)[0x7efd60be56b6]
/lib/x86_64-linux-gnu/libc.so.6(+0x74e9e)[0x7efd60be5e9e]
server[0x8e140c]
server(_ZN9cpp_redis7network4unix10io_service8write_fdEi+0x110)[0x8e3900]
server(_ZN9cpp_redis7network4unix10io_service12process_setsEP6pollfdm+0x19a)[0x8e3b6a]
server(_ZN9cpp_redis7network4unix10io_service10process_ioEv+0x50)[0x8e3c70]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xb998f)[0x7efd614e698f]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7464)[0x7efd6228d464]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7efd60c5830d]

Personally, I think the following is suspicious:

for (int fd : fds_to_write) { write_fd(fd); }

In the body of write_fd, it is possible to remove an fd inside that loop here: https://github.com/Cylix/cpp_redis/blob/master/sources/network/unix/io_service.cpp#L130

Thoughts?

Disconnect issue

There is a disconnect issue in the examples that puzzles me. The sigint_handler and the subsequent disconnection handler are invoked upon sending the interrupt signal, but the main function does not terminate.

Adding a sleep(1) inside the "while (not should_exit);" loop appears to solve the termination issue, but is there possibly a disconnect/threading issue at play here?

Thank you for a nice Redis client!

Hang on sync_commit()

We have a sync_commit call that works fine most of the time, but on occasion it seems to hang on the following line:

m_sync_condvar.wait(lock_callback, [=] { return m_callbacks_running == 0 && m_callbacks.empty(); });

m_callbacks_running is 0 and m_callbacks is empty, but it looks like the condition variable is not being notified? It just waits forever and nothing makes progress. I'm not really sure how to debug this!

libc++abi.dylib: terminating with uncaught exception of type cpp_redis::redis_error: connect() failure

I get this error when I run my program,.
I'm sure that the redis-server is ok, and I could sub message in redis-cli and pyredis.
My code is

#include <iostream>
#include "CheatWorker.h"
#include <cpp_redis/cpp_redis>
volatile std::atomic<bool> should_exit = ATOMIC_VAR_INIT(false);
int main(int argc, char *argv[]) {
    std::cout << "Hello, World!" << std::endl;
    cpp_redis::redis_subscriber client;
    client.connect("127.0.0.1", 6397, [](cpp_redis::redis_subscriber&) {
        std::cout << "sub disconnected. " << std::endl;
        should_exit = true;
    });
    /*
    client.subscribe("cheat", [](const std::string& chan, const std::string& msg) {
        std::cout << "Message (" << msg << ") from channel " << chan << std:: endl;
    });
    client.commit();
     */
    return 0;
}

I have searched in google, and it seems that this exception is caused by the type error.
Could you please help me solve this?

How do i convert a cpp_redis::reply to a std::string

I have this snippet of code that does not compile.

vector<string> rics;
    redis_client.smembers("quote_alerts", [rics](cpp_redis::reply& reply) {
        for(auto r: reply.as_array()) {
            rics.push_back(r);
        }
    });

I get the following compile time error

 error: no matching function for call to ‘std::vector<std::__cxx11::basic_string<char> >::push_back(cpp_redis::reply&) const’
             rics.push_back(r);

How do I take the response and make a vector<string> out of it?

cmake policy CMP0042 doesn't exist in cmake version 2.8.1

There is a little inconsistency in CMakeLists.txt in these lines:

cmake_minimum_required(VERSION 2.8.1)
cmake_policy(SET CMP0042 NEW)

Problem is CMP0042 was introduced in CMake version 3.0 (https://cmake.org/cmake/help/v3.0/policy/CMP0042.html)

Probably the easiest solution is to set minimum required version of CMake to 3.0.

But I've encountered this problem on Ubuntu 14.04, where default CMake verison is 2.8.12.
To fix CMake errors I've replace the first two commands with following:

cmake_minimum_required(VERSION 2.8.12)
set(CMAKE_MACOSX_RPATH 1)

Hello

After testing all of the C++ Redis libs I've stayed with the yours one. :) Simple and powerfull!

However I have experience one problem - after client got disconnected from redis it is not possible to reconnect back to redis server. After calling connect() the application freeze.

Redis client hangs when using lrange to get a list

I am using the lrange command to get part of the values from the a large list (>10M)
redisClient.lrange(key, start, end,[&](reply& reply) {
//code logic here
});
If I retrieve 30 or 40 items from the list at one call, the application works fine.
But if I get more than 40 items such as 500 items, the redis client will hang and the call back is never triggered. I wonder if there is some internal buffer in the client and if the value exceeds the buffer, the application will hang.
I am working on Windows and using VisualStudio 2013 with CTP_Nov2013 compiler.

Some issues concerning the network module

Some issues are reported concerning the network part. (#19 #21 #24 #25)
One is concerning the unix version, the other are mostly concerning the windows port.

I am currently working on an external library providing networking TCP features in a much-enhanced design.

This external library is intended to replace the networking module of cpp_redis and this should fix these issues.

warning Two or more files with the name of reply.cpp

I'm working on a Windows build of your library.
The changes to support WIN32 were not bad at all.

However, I'm having this issue:

_warning MSB8027: Two or more files with the name of reply.cpp will produce outputs to the same location. This can lead to an incorrect build result. The files involved are sources\replies\reply.cpp, sources\reply.cpp._

It looks like the 'reply' class exists in both files.
However the top one contains these extra methods:

array_reply& as_array(void);
bulk_string_reply& as_bulk_string(void);
error_reply& as_error(void);
integer_reply& as_integer(void);
simple_string_reply& as_simple_string(void);

The test project needs the extra methods.
Can we unify these so there is only one reply hpp and cpp?
Run a compare tool on the two files so you can see the difference.

Thanks,
Mike M.

P.S Awesome work! I'm almost ready to run the tests...

Program hangs up (probably not an issue but a feature request)

Hello,
if I try to run

int _tmain(int argc, _TCHAR* argv[])
{
	cpp_redis::redis_client client;
	std::cout << "beppe " << std::endl;
	return 0;
}

the program prints "beppe" and than hangs up. I think because the running threads do not terminate.
Is it possible to add a function that close all threads and permit the program to terminate?
Thank you
Simone

Multithreaded mismatch

This line on both tacopie and cpp_redis CMakeLists.txt is causing problems on my environment (VS2015 with CMake 3.7):
string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")

I get errors like error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' .
I just commented out these lines and it builds. But this makes it impossible to use this lib simply as a submodule in my project.

Link Error in Visual Studio 2015

The cpp_redis build is fine in both Debug/Release mode. And I copied the cpp_redis.lib and tacopie.lib to my project folder and referred them in the project setting. I got some link errors when trying to build:

1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_accept referenced in function "public: class tacopie::tcp_socket __cdecl tacopie::tcp_socket::accept(void)" (?accept@tcp_socket@tacopie@@qeaa?AV12@XZ)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_bind referenced in function "public: void __cdecl tacopie::tcp_socket::bind(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,unsigned int)" (?bind@tcp_socket@tacopie@@QEAAXAEBV?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@i@Z)
1>tacopie.lib(self_pipe.obj) : error LNK2001: unresolved external symbol __imp_bind
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_closesocket referenced in function "public: void __cdecl tacopie::tcp_socket::close(void)" (?close@tcp_socket@tacopie@@QEAAXXZ)
1>tacopie.lib(self_pipe.obj) : error LNK2001: unresolved external symbol __imp_closesocket
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_connect referenced in function "public: void __cdecl tacopie::tcp_socket::connect(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,unsigned int)" (?connect@tcp_socket@tacopie@@QEAAXAEBV?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@i@Z)
1>tacopie.lib(self_pipe.obj) : error LNK2001: unresolved external symbol __imp_connect
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_htons referenced in function "public: void __cdecl tacopie::tcp_socket::connect(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,unsigned int)" (?connect@tcp_socket@tacopie@@QEAAXAEBV?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@i@Z)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_listen referenced in function "public: void __cdecl tacopie::tcp_socket::listen(unsigned __int64)" (?listen@tcp_socket@tacopie@@QEAAX_K@Z)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_recv referenced in function "public: class std::vector<char,class std::allocator > __cdecl tacopie::tcp_socket::recv(unsigned __int64)" (?recv@tcp_socket@tacopie@@qeaa?AV?$vector@DV?$allocator@D@std@@@std@@_K@Z)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_send referenced in function "public: unsigned __int64 __cdecl tacopie::tcp_socket::send(class std::vector<char,class std::allocator > const &,unsigned __int64)" (?send@tcp_socket@tacopie@@QEAA_KAEBV?$vector@DV?$allocator@D@std@@@std@@_K@Z)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_socket referenced in function "private: void __cdecl tacopie::tcp_socket::create_socket_if_necessary(void)" (?create_socket_if_necessary@tcp_socket@tacopie@@AEAAXXZ)
1>tacopie.lib(self_pipe.obj) : error LNK2001: unresolved external symbol __imp_socket
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_getaddrinfo referenced in function "public: void __cdecl tacopie::tcp_socket::connect(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,unsigned int)" (?connect@tcp_socket@tacopie@@QEAAXAEBV?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@i@Z)
1>tacopie.lib(tcp_socket.obj) : error LNK2019: unresolved external symbol __imp_freeaddrinfo referenced in function "public: void __cdecl tacopie::tcp_socket::connect(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,unsigned int)" (?connect@tcp_socket@tacopie@@QEAAXAEBV?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@i@Z)
1>tacopie.lib(io_service.obj) : error LNK2019: unresolved external symbol __imp_WSAPoll referenced in function "private: void __cdecl tacopie::io_service::poll(void)" (?poll@io_service@tacopie@@AEAAXXZ)
1>tacopie.lib(self_pipe.obj) : error LNK2019: unresolved external symbol __imp_ioctlsocket referenced in function "public: __cdecl tacopie::self_pipe::self_pipe(void)" (??0self_pipe@tacopie@@qeaa@XZ)
1>tacopie.lib(self_pipe.obj) : error LNK2019: unresolved external symbol __imp_getsockname referenced in function "public: __cdecl tacopie::self_pipe::self_pipe(void)" (??0self_pipe@tacopie@@qeaa@XZ)
1>tacopie.lib(self_pipe.obj) : error LNK2019: unresolved external symbol __imp_htonl referenced in function "public: __cdecl tacopie::self_pipe::self_pipe(void)" (??0self_pipe@tacopie@@qeaa@XZ)
1>tacopie.lib(self_pipe.obj) : error LNK2019: unresolved external symbol __imp_recvfrom referenced in function "public: void __cdecl tacopie::self_pipe::clr_buffer(void)" (?clr_buffer@self_pipe@tacopie@@QEAAXXZ)
1>tacopie.lib(self_pipe.obj) : error LNK2019: unresolved external symbol __imp_sendto referenced in function "public: void __cdecl tacopie::self_pipe::notify(void)" (?notify@self_pipe@tacopie@@QEAAXXZ)

Are there any dependencies required for building? I am using Visual Studio 2015.

Is it possible to use "sync_commit" in subscribe callback?

Hi,
The code I am trying to run is below:

auto func_subscribe_reply = [=](const std::string& chan, const std::string& msg) {

	std::cout << "subscribe_reply : " << chan << " || " << msg << "\n";

	client.get("test_value", [](cpp_redis::reply& reply) {
		std::cout << "get test_value: " << reply << std::endl;
		 if (reply.is_string())
			 std::cout << "test_value : " << reply.as_string() << "\n";
	}).sync_commit();

	// I need to use test_value in here.
};

subscriber.subscribe("test_channel", func_subscribe_reply).commit();

m_sync_condvar waits forever in sync_commit. commit is doing great but I need to use the test_value where I pointed out. I don't know even if my question is logical, please excuse my lack of knowledge.

Thank you.

missing callback for mget with 10.000 keys

Hello, I'm trying to mget 10.000 entries a 20 bytes long. It works with 3999 values, but not with 4000 - I don't get the call back in this case. The redis-server recieves the call properly.

Example:
void testSetup()
{
cpp_redis::redis_client client;
client.connect();
char key[1000];
std::string value(20, 'v');
for (int i = 0; i != 10000; ++i)
{
sprintf(key, "k%d", i);
client.set(key, value);
}
client.sync_commit();
client.disconnect();
}

void testRun()
{
cpp_redis::redis_client client;
client.connect();
char key[1000];
std::vectorstd::string keys;
keys.reserve(10000);
for (int i = 0; i != 10000; ++i)
{
sprintf(key, "k%d", i);
keys.push_back(key);
}

client.mget(keys, [] (cpp_redis::reply & reply) {
    if (reply.is_array())
        std::cout << "got " << reply.as_array().size() << " values\n";
});

client.commit();
std::this_thread::sleep_for(std::chrono::seconds(1000));
client.disconnect();

}

CPU pegged at 100% when use redis_subscriber.connect

Just wanted to start with - great library!!

I'm currently using the redis_subscriber to receive notifications. My use case is very simple - I get a notification, I record a timestamp. Notifications are very rare.
However, I was noticing my program was often consuming 100% of 1 CPU (kernel space) - after it started and before I put any load or actually received any notifications.

Program worked fine when - just the 1 CPU was pegged. After much narrowing, I've narrowed it down to the redis_subscriber.connect triggers the issue.

Also, it appears the issue always happens when I run on a single-CPU Ubuntu 16 VM. On a Ubuntu VM with more than 1 CPU, the issue is much less common (though it does happen).

The code is pretty straight forward:

void
CacheSubscriber::State::initConnection()
{
    this->doConnInit = false;
    updateCacheTime();
    this->subscriber.connect( this->hostname, this->port, [this](redis_subscriber& sub)
    {
        if ( !this->shutdown )   {  this->doConnInit = true;    }
    });
    this->subscriber.subscribe( this->channel, [this](const std::string& channel, const std::string& msg)
    {
        if ( this->channel == channel )   {  updateCacheTime();   }
    });

    this->subscriber.commit();
}

If there is any additional info I can provide - let me know...

Concurrency issue

Having an application using both a redis_client and a redis_subscriber I receive numerous errors from Valgrind when destructing these objects. Possibly have something to do with destroying the redis_connections, but I'm not sure.

The problem can be reproduced by modifying the redis_subscriber example adding an instance of a redis_client and making a connect() on this object. See attached files.

Modified redis_subscriber
redis_subscriber.cpp.txt

Valgrind output
valgrind_output.txt

crash when disconnect after commit in windows

tcp_client::disconnect whill call io_service::untrack to erase sock_info,
but this sock_info may used in io_service::process_io

auto redis_sub = new cpp_redis::redis_subscriber();
redis_sub->psubscribe(xxx);
redis_sub->commit();
delete redis_sub;

Hang on Windows 7 64 bit, VS2015.

If I run this code in VS2015

WORD version = MAKEWORD(2, 2);
	WSADATA data;

	if (WSAStartup(version, &data) != 0) {
		std::cerr << "WSAStartup() failure" << std::endl;
		return false;
	}
cpp_redis::redis_client client;
client.connect();
client.set("hello", "42");
client.get("hello", [](cpp_redis::reply& reply) {
  std::cout << reply << std::endl;
});
client.commit();
WSACleanup();
	return 0;

I get threads stuck at shutdown of the executable.
This is the callstack of the mainthread

        Example.exe!std::thread::join() Line 214	C++
 	Example.exe!tacopie::io_service::~io_service() Line 75	C++
...
 	Example.exe!std::shared_ptr<tacopie::io_service>::~shared_ptr<tacopie::io_service>() Line 611	C++
 	Example.exe!tacopie::`dynamic atexit destructor for 'io_service_default_instance''()	C++

which is stuck at

io_service::~io_service(void) {
  __TACOPIE_LOG(debug, "destroy io_service");

  m_should_stop = true;
  m_notifier.notify();
--> STUCK  **m_poll_worker.join();** 
  m_callback_workers.stop();

}


This is the callstack of thread 2

 	Example.exe!tacopie::utils::thread_pool::fetch_task() Line 103	C++
 	Example.exe!tacopie::utils::thread_pool::run() Line 54	C++

Which is stuck at


thread_pool::fetch_task(void) {
  std::unique_lock<std::mutex> lock(m_tasks_mtx);

  __TACOPIE_LOG(debug, "waiting to fetch task");

 --> STUCK m_tasks_condvar.wait(lock, [&] { return m_should_stop || !m_tasks.empty(); });

  if (m_tasks.empty()) { return nullptr; }

  task_t task = std::move(m_tasks.front());
  m_tasks.pop();
  return task;
}

Any clue, idea how I could tell ioservice and threadpool that there is no more point in waiting for things, that will never happen?

CMake compilation options for VC++

I tried using CMake to build the Visual Studio 2015 project files for cpp_redis.

I ran into an issue when trying to compile using the generated project.

This line:
## set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -W -Wall -Wextra -O3")

is not valid for Visual Studio 2015.
I don't know a thing about gcc compiler so I'll I tried to find documentation to convert these flags for VC++.

It complains about the -W flag.
I believe these options are what you want for VC++
/W3 - Warning Level 3 (any lower produces errors)
/O2 - Creates fast code (Don't want this for Debug build)

There is no option for c++11 (it's on by default)
Which would give you the following CMake line for a Release build.

## set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W3 -O2 -D "_UNICODE" -D "UNICODE" -D "WIN32_LEAN_AND_MEAN")

I have no clue how to use CMake or to put in conditional statements for the environment.
Can you merge this fix in?
For reference here's a web link to VC++ compiler flags: https://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx

Also could you make the default project a Static Library as opposed to a DLL (or maybe support both)?
Lastly the 'tests" project is not automatically built by CMake.

FYI I'll create a branch for the Windows port of cpp_redis. This library is exactly what I've been looking for!
Mike M.

massive loading problems

Hello,

I'm running redis under Mac OS X 10.11.4, but I have some problems with loading some data: Here is the output. It seems the data has been sent too fast to be handled properly with client.

Attached there's my source code.

`include

include

include <cpp_redis/cpp_redis>

cpp_redis::redis_client client;

int main(int argc, char* argv[]) {
client.connect();

std::string arg (" ");
int size = 100;

for(auto i=1;i<=size;i++) {
std::cout << "Deleting hash cta:"+std::to_string(i) << std::endl;
client.send({"HDEL ", "cta:"+std::to_string(i)});
std::cout << "DONE DEL" << std::endl;
}

std::cout << "creating values default" << std::endl;

for(auto i=1;i<=size;i++)
arg += " v" + std::to_string(i)+ " -1";
std::cout << "DONE DEL" << std::endl;
}

std::cout << "creating values default" << std::endl;

for(auto i=1;i<=size;i++)
arg += " v" + std::to_string(i)+ " -1";

std::cout << arg << std::endl;

for(auto i=1;i<=size;i++) {
std::cout << "Creating hash cta:"+std::to_string(i) << std::endl;
client.send({"HMSET", "cta:"+std::to_string(i), arg}, [](cpp_redis::reply& reply) {
std::cout << reply.as_string() << std::endl;
});

std::cout << "DONE CREATE" << std::endl;

}

client.disconnect();

return 0;
}`

Creating hash cta:1
DONE CREATE
Creating hash cta:2
DONE CREATE
Creating hash cta:3
DONE CREATE
Creating hash cta:4
DONE CREATE
Creating hash cta:5
DONE CREATE
Creating hash cta:6
DONE CREATE
Creating hash cta:7
DONE CREATE
Creating hash cta:8
DONE CREATE
Creating hash cta:9
DONE CREATE
ERCRr ewartoinngg nhuamsbhe rc toaf: 1a0r
guments for 'hmset' command
DONE CREATE
Creating hash cta:11
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:12
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:13
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:14
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:15
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:16
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:17
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:18
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:19
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:20
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:21
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:22
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:23
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:24
ERR wrong number of arguments for 'hmset' command
DONE CREATEERR wrong number of arguments for 'hmset' command
ERR wrong number of arguments for 'hmset' command
ERR wrong number of arguments for 'hmset' command
ERR wrong number of arguments for 'hmset' command

Creating hash cta:25
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:26
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:27
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:28
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:29
ERR wrong number of arguments for 'hmset' command
DONE CREATE
ERCRr ewartoinngg nhuamber of arguments for 'hmset' commansdh
cEtRaR: 3w0r
ong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:31
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:32
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:33
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:34
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:35
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:36
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:37
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:38
DONE CREATE
Creating hash cta:39
DONE CREATE
Creating hash cta:40
DONE CREATE
Creating hash cta:41
DONE CREATE
Creating hash cta:42
DONE CREATE
Creating hash cta:43
DONE CREATE
Creating hash cta:44
DONE CREATE
Creating hash cta:45
DONE CREATE
Creating hash cta:46
DONE CREATE
ERCRr ewartoinngg nhuamsbhe rc toaf: 4a7r
guments for 'hmset' command
DONE CREATE
Creating hash cta:48
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:49
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:50
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:51
DONE CREATE
Creating hash cta:52
DONE CREATE
Creating hash cta:53
DONE CREATE
Creating hash cta:54
DONE CREATE
Creating hash cta:55
DONE CREATE
Creating hash cta:56
DONE CREATE
Creating hash cta:57
DONE CREATE
Creating hash cta:58
DONE CREATE
Creating hash cta:59
DONE CREATE
Creating hash cta:60
DONE CREATE
Creating hash cta:61
DONE CREATE
Creating hash cta:62
DONE CREATE
Creating hash cta:63
DONE CREATE
Creating hash cta:64
DONE CREATE
Creating hash cta:65
DONE CREATE
Creating hash cta:66
DONE CREATE
Creating hash cta:67
DONE CREATE
Creating hash cta:68
DONE CREATE
Creating hash cta:69
DONE CREATE
Creating hash cta:70
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:71
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:72
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:73
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:74
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:75
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:76
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:77
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:78
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:79
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:80
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:81
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:82
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:83
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:84
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:85
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:86
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:87
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:88
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:89
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:90
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:91
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:92
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:93
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:94
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:95
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:96
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:97
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:98
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:99
ERR wrong number of arguments for 'hmset' command
DONE CREATE
Creating hash cta:100
ERR wrong number of arguments for 'hmset' command
DONE CREATE
ERR wrong number of arguments for 'hmset' command
ERR wrong number of arguments for 'hmset' command

Linking to tacopie (libtacopie.a)

Hi all,

First of all: thanks for the good docs and clean project, very refreshing!

I installed cpp_redis as described in https://github.com/Cylix/cpp_redis/wiki/Mac-&-Linux-Install
Now I ran into a two linking problems regarding tacopie.

  1. I forgot to link to it at first even though it's clearly written in the wiki, however, it is not included in the example CMakelists.txt.

  2. When I realized that I needed to link to tacopie, I found that it is not installed into /usr/local/lib. My current workaround is:

    target_link_libraries(mywhatever
        cpp_redis
        $ENV{HOME}/src/cpp_redis/deps/lib/libtacopie.a
        pthread
    )
    

What am I doing wrong?

Question: How to use multi exec with sync_client?

I wrote code like this:

    cpp_redis::sync_client& sync_client = _refRedisHandler->GetSyncClient();
sync_client.multi();
cpp_redis::reply reply = sync_client.smembers(_sIdHashDirty);
sync_client.del(std::vector<std::string>{ _sIdHashDirty });
sync_client.exec();

But the reply is always in queued state. How can I get the result after transaction?

subscriber does not work on windows

Hey,
Thanks for creating this project. I think its sorely needed and very well made.

I find that the Subscriber is not working on windows.
I just copied your redis_subscriber.cpp example into the TEST project on windows

  • loaded #pragma comment(lib,"WS2_32") and ran it.

It connects to redis makes a subscription - and shows as subscribed on redis. But the subscription callback is not called. Once in a while a single message might make it through - but never more than that. something seems to be wrong here.

Please take a look.
thanks,

Subscriber + AUTH

Hi, I have started using this lib yesterday so, I'm still kinda new here...

I'm looking for a way to create a subscription and auth at the same time, is that possible?
I made my client (publisher) auth without any problems, but I can't find any way to auth the subscriber.

Can someone give me a little help here?

linux write data 100% cpu

Thread 4 (Thread 0x7f6ca5eaa700 (LWP 910)):
#0 0x00007f6cacedc933 in select () from /lib64/libc.so.6
#1 0x00000000004ad6fa in tacopie::io_service::poll() ()
#2 0x00007f6cad77d230 in ?? () from /lib64/libstdc++.so.6
#3 0x00007f6cacbdadf3 in start_thread () from /lib64/libpthread.so.0
#4 0x00007f6cacee51ad in clone () from /lib64/libc.so.6

Threads: 2344 total, 3 running, 2341 sleeping, 0 stopped, 0 zombie
%Cpu(s): 21.0 us, 32.5 sy, 0.0 ni, 46.3 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem: 16269700 total, 15801636 used, 468064 free, 158872 buffers
KiB Swap: 0 total, 0 used, 0 free. 2272844 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
910 root 20 0 416432 1336 980 R 99.8 0.0 46:30.66 PlayBackServer

Heap use after free memory

Hello together,

first of all thanks for this well written C++ redis library code.

I integrated your library into my own private repository. After playing with it, I detect some issue in case of the standard disconnection handling.

The class redis_connection contains the function disconnect with a "wait_for_removal" flag which is predefined as false.

void disconnect(bool wait_for_removal = false);

The class redis_client has got a deconstructor which is using this function with the "wait_for_removal" flag predefined as true.

redis_client::~redis_client(void) { m_client.disconnect(true); /* parameter = true */ __CPP_REDIS_LOG(debug, "cpp_redis::redis_client destroyed"); }

The class redis_client also uses the mentioned function above in such a way that this flag is false:

void redis_client::disconnect(void) { __CPP_REDIS_LOG(debug, "cpp_redis::redis_client attempts to disconnect"); m_client.disconnect(); /* no parameter = false */ __CPP_REDIS_LOG(info, "cpp_redis::redis_client disconnected"); }

So when I´m explicitly using the disconnect-function from a redis_client object, the wait_for_removal flag is always false. Because of this, I get a "heap use after free" memory issue while I was connecting / disconnecting repeatedly. In the issue case, the disconnection has been closed without waiting for removal. While this happened, an async_read gets executed and the error occured.

Check my address sanitizer logfile for further information.

Is this expected behavior from your side? Am I using the disconnection function wrong or did you forget setting the flag predefined as true?

Thanks in advance,

Altavist

asan.txt

cpp_redis can't correctly handle "Null reply".

Hi.
I use transactions with redis.
When using WATCH, EXEC can return a "Null reply" if the execution was aborted. But in this case callback is not triggered.

Steps.

  1. Call WATCH for some "key".
  2. From other client call SET "key" ...
  3. From first app call MULTI and EXEC.
  4. Last call of sync_commit() return, but callback for EXEC is not triggered.

Then I have tried to debug cpp_redis and found that it can't process reply like "*-1\r\n".
It throw exception in
bool array_builder::fetch_array_size(std::string& buffer)

Thanks.

blpop is blocking?

Hello,
I am trying to use blpop to implement a queue

I run the program

#include "cpp_redis/cpp_redis"

volatile std::atomic_bool should_exit = ATOMIC_VAR_INIT(false);

void
sigint_handler(int) {
	should_exit = true;
}

int main(int argc, _TCHAR* argv[])
{
	cpp_redis::redis_client client;
	client.connect("lx000000010550", 6379, [](cpp_redis::redis_client&) {
		std::cout << "client disconnected (disconnection handler)" << std::endl;
		should_exit = true;
	});

	signal(SIGINT, &sigint_handler);
	while (!should_exit) {
		client.blpop({ "key_queue" }, 0, [](cpp_redis::reply& reply) {
			std::cout << "decrby hello 12: " << reply << std::endl;
		});
		client.commit();
		std::cout << "NEVER STOP" << std::endl;
	}
	client.disconnect();

	return 0;
}

It enters in a infinite loop printing "NEVER STOP" and the CPU load of the computer raises.
I'd want it block on the instruction

client.blpop({ "key_queue" }, 0, [](cpp_redis::reply& reply) {
			std::cout << "decrby hello 12: " << reply << std::endl;
		});

and I'd want to have no CPU load.

Is it possible?

Thank you

Simone

cannot convert from 'bool' to 'volatile std::atomic_bool

Hello,
I am using cpp_redis with:
Microsoft Visual Studio Professional 2013
Version 12.0.40629.00 Update 5
and I am having the error cannot convert from 'bool' to 'volatile std::atomic_bool that I can resolve with ATOMIC_VAR_INIT(false);

For example, from
std::atomic_bool callback_run(false);
to
std::atomic_bool callback_run = ATOMIC_VAR_INIT(false);
Is it a good solution?
Thank you
Simone

Crash when cpp_redis::redis_client is a static variable

There is a std::bad_function_call exception raise when i define cpp_redis::redis_client as a static variable.

The code is quite simple.

#include <cpp_redis>
cpp_redis::redis_client client;
int main() {
    return 0;
}

I use clion in ubuntu.
Looking forward to your reply.
Thanks.

Use of the singleton pattern leads to "use after free"

The cpp_redis::network::io_service is implemented as a singleton.
The problem with that is, that in some cases the destructor for io_service is called before the destructor of redis_client and this leads to "use after free".

Example log from valgrind:

==5190== Invalid read of size 8
==5190==    at 0x9FE3258: _M_find_before_node (hashtable.h:1413)
==5190==    by 0x9FE3258: _M_erase (hashtable.h:1779)
==5190==    by 0x9FE3258: erase (hashtable.h:751)
==5190==    by 0x9FE3258: erase (unordered_map.h:776)
==5190==    by 0x9FE3258: cpp_redis::network::io_service::untrack(int) (io_service.cpp:176)
==5190==    by 0x9FE66D5: cpp_redis::network::tcp_client::disconnect() (tcp_client.cpp:76)
==5190==    by 0x9FCE8E7: cpp_redis::redis_client::~redis_client() (redis_client.cpp:8)
==5190==    by 0x9DB1A71: ~ModuleData (ModuleData.h:19)
<snip....>
==5190==    by 0x67CD98F: __run_exit_handlers (in /usr/lib/libc-2.24.so)
==5190==    by 0x67CD9E9: exit (in /usr/lib/libc-2.24.so)
==5190==    by 0x67B8297: (below main) (in /usr/lib/libc-2.24.so)
==5190==  Address 0xb444c20 is 0 bytes inside a block of size 16 free'd
==5190==    at 0x4C2C20A: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5190==    by 0x9FE2757: deallocate (new_allocator.h:110)
==5190==    by 0x9FE2757: deallocate (alloc_traits.h:442)
==5190==    by 0x9FE2757: _M_deallocate_buckets (hashtable_policy.h:2008)
==5190==    by 0x9FE2757: _M_deallocate_buckets (hashtable.h:355)
==5190==    by 0x9FE2757: _M_deallocate_buckets (hashtable.h:360)
==5190==    by 0x9FE2757: ~_Hashtable (hashtable.h:1228)
==5190==    by 0x9FE2757: ~unordered_map (unordered_map.h:98)
==5190==    by 0x9FE2757: cpp_redis::network::io_service::~io_service() (io_service.cpp:29)
==5190==    by 0x67CD98F: __run_exit_handlers (in /usr/lib/libc-2.24.so)
==5190==    by 0x67CD9E9: exit (in /usr/lib/libc-2.24.so)
==5190==    by 0x67B8297: (below main) (in /usr/lib/libc-2.24.so)

Single callback for command pipeline

I'm trying to grab multiple hashes at once. Something like this.

I would expect to provide a single callback to execute at the end of the pipeline to retrieve all of the values, but I'm not sure how to structure it using the chained send calls. Is such a thing possible using this client? It seems I would have to provide a separate callback for every item in the list, which doesn't make much sense to me.

there is a assert happend if call the cppredis::publish function in multithread at debug mode?

as my issue says:there is a assert happend if call the cppredis::publish function in multithread at debug mode?
the code is in tcp_client.cpp line 191
191: if (length >= m_write_buffer.front().size())
m_write_buffer.pop_front();
else
m_write_buffer.front().erase(m_write_buffer.front().begin(), m_write_buffer.front().begin() + length);
the std::list::front() function is directly use *begin(),so if m_write_buffer is empty ,the begin() iterator is equal end() ,is a invalid iterator,and VC++ will report a assertion .
my suggestion is add some code before line 191 like this
if(m_write_buffer.empty())
return;
sorry for my poor english...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.