diff --git a/app/wizard_demo/pkv/CMakeLists.txt b/app/wizard_demo/pkv/CMakeLists.txt new file mode 100644 index 000000000..4dfe4655b --- /dev/null +++ b/app/wizard_demo/pkv/CMakeLists.txt @@ -0,0 +1,114 @@ +cmake_minimum_required(VERSION 2.8) +project(pkv) + +if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + message(FATAL_ERROR "Please into another dir to build!") +endif() + +if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + message(FATAL_ERROR "Please into another dir to build!") +endif() + +if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") + message(STATUS "build pkv for release version") +elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") + message(STATUS "build pkv for debug version") +else() + message(STATUS "build pkv for default version") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + add_definitions("-Wno-invalid-source-encoding") + include_directories("/usr/local/include") + SET(CMAKE_CXX_ARCHIVE_CREATE " Scr ") + SET(CMAKE_CXX_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") +elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") +else() + message(FATAL_ERROR "unknown CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}") +endif() + +############################################################################## + +set(home_path ${CMAKE_CURRENT_SOURCE_DIR}/../../..) +set(acl_path ${home_path}/lib_acl) +set(acl_cpp_path ${home_path}/lib_acl_cpp) +set(fiber_path ${home_path}/lib_fiber/c) +set(fiber_cpp_path ${home_path}/lib_fiber/cpp) + + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${acl_path}/include + ${acl_cpp_path}/include + ${fiber_path}/include + ${fiber_cpp_path}/include +) + +set(base_path ${CMAKE_CURRENT_SOURCE_DIR}) +set(src_paths + ${base_path} + ${base_path}/action + ${base_path}/dao + ${base_path}/db + ${base_path}/db/rocksdb + ${base_path}/db/wt + ${base_path}/proto +) + +foreach(iter ${src_paths}) + aux_source_directory(${iter} src_files) +endforeach() + +############################################################################## + +#SET(CMAKE_VERBOSE_MAKEFILE on) + +add_definitions( + "-g" + "-W" + "-Wall" + "-Werror" + "-Wshadow" + "-Wformat" + "-Wpointer-arith" + "-D_REENTRANT" + "-Wno-long-long" + "-Wuninitialized" + "-D_POSIX_PTHREAD_SEMANTICS" + "-fexceptions" + "-Wno-unused-parameter" + "-Wno-error=deprecated-declarations" + "-Wno-deprecated-declarations" + "-fPIC" + "-std=c++17" + "-DHAS_ROCKSDB" +) + +#find_library(acl_lib acl_all PATHS /usr/lib /usr/local/lib) +#find_library(fiber_cpp_lib fiber_cpp PATHS /usr/lib /usr/local/lib) +#find_library(fiber_lib fiber PATHS /usr/lib /usr/local/lib) + +#find_library(rocksdb_lib rocksdb PATHS /usr/lib /usr/local/lib) + +set(acl_all ${home_path}/lib_fiber/lib/libfiber_cpp.a ${home_path}/libacl_all.a) +set(fiber ${home_path}/lib_fiber/lib/libfiber.a) +set(rocksdb /usr/local/lib/librocksdb.a) + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") +# set(lib_all ${lib_global} ${lib_rpc} ${fiber_cpp_lib} ${acl_lib} ${fiber_lib} + set(lib_all ${acl_all} + ${rocksdb} ${fiber} -liconv -lz -lpthread -ldl) +elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") +# set(lib_all ${lib_global} ${lib_rpc} ${fiber_cpp_lib} ${acl_lib} ${fiber_lib} + set(lib_all ${acl_all} + ${rocksdb} -lwiredtiger ${fiber} -luring -liconv -lz -lpthread -ldl) +endif() + +set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) +link_directories(${output_path}) + +add_executable(pkv ${src_files} action/redis_handler.cpp action/redis_handler.h) +target_link_libraries(pkv ${lib_all}) + +############################################################################### diff --git a/app/wizard_demo/pkv/Makefile b/app/wizard_demo/pkv/Makefile new file mode 100644 index 000000000..22975ed7d --- /dev/null +++ b/app/wizard_demo/pkv/Makefile @@ -0,0 +1,7 @@ +all: + @(mkdir -p build; cd build; cmake ..; make -j 4) + +clean cl: + @(rm -rf build pkv) + +rebuild rb: cl all diff --git a/app/wizard_demo/pkv/Makefile.in b/app/wizard_demo/pkv/Makefile.in new file mode 100644 index 000000000..4e262892f --- /dev/null +++ b/app/wizard_demo/pkv/Makefile.in @@ -0,0 +1,189 @@ +CC = g++ + +CFLAGS = -c -g -W \ +-Wall \ +-Wcast-qual \ +-Wcast-align \ +-Wno-long-long \ +-Wpointer-arith \ +-Werror \ +-Wshadow \ +-O3 \ +-D_REENTRANT \ +-D_POSIX_PTHREAD_SEMANTICS \ +-D_USE_FAST_MACRO +CFLAGS += --std=c++17 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lz -ldl +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -s) +OSTYPE = $(shell uname -m) +RPATH = linux64 + +OS_ENV=$(shell uname -a) +ifeq ($(findstring WSL, $(OS_ENV)), WSL) + SYSLIB += -liconv +endif + +ifeq ($(findstring ubuntu, $(OS_ENV)), ubuntu) + SYSLIB += -liconv +endif + +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring Alpine, $(shell uname -a)), Alpine) + SYSLIB += -lucontext +endif + +ifeq ($(findstring g++, $(CC)), g++) + GCC_VERSION=$(shell g++ --version | grep ^g++ | sed 's/^.* //g') + GCC_MAJOR:=$(shell echo "$(GCC_VERSION)" | cut -d'.' -f1) + GCC_MINOR:=$(shell echo "$(GCC_VERSION)" | cut -d'.' -f2) + GCC_SUB:=$(shell echo "$(GCC_VERSION)" | cut -d'.' -f3) + GCC_VER:=$(shell [ $(GCC_MAJOR) -gt 4 -o \( $(GCC_MAJOR) -eq 4 -a $(GCC_MINOR) -gt 7 \) ] && echo true) +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread -lz + RPATH = freebsd +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) +# CC += -arch x86_64 -arch arm64 + CFLAGS += -DMACOSX -Wno-invalid-source-encoding \ + -Wno-invalid-offsetof \ + -DHAS_ROCKSDB + UNIXTYPE = MACOSX + SYSLIB += -liconv -rdynamic -lz + RPATH = macos +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + has_io_uring=$(HAS_IO_URING) + ifeq ($(has_io_uring), yes) + SYSLIB += -luring-ffi + endif + + CFLAGS += -DLINUX2 -D_REENTRANT -DHAS_ROCKSDB + SYSLIB += -lcrypt -lz -lunwind -lunwind-generic +endif + +# For CYGWIN +ifeq ($(findstring CYGWIN, $(UNIXNAME)), CYGWIN) + SYSLIB = -lpthread -liconv -lz + CFLAGS += -DLINUX2 -DMINGW + UNIXTYPE = LINUX +endif + +# For MINGW +ifeq ($(findstring MINGW, $(UNIXNAME)), MINGW) + SYSLIB = -lpthread -liconv -lz + CFLAGS += -DLINUX2 -DMINGW + UNIXTYPE = LINUX +endif + +# For MSYS +ifeq ($(findstring MSYS, $(UNIXNAME)), MSYS) + SYSLIB = -lpthread -liconv -lz + CFLAGS += -DLINUX2 -DMINGW + UNIXTYPE = LINUX +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT + RPATH = sunos_x86 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../.. +CFLAGS += -I. -I$(ACL_PATH)/lib_acl/include \ + -I$(ACL_PATH)/lib_protocol/include \ + -I$(ACL_PATH)/lib_acl_cpp/include \ + -I$(ACL_PATH)/lib_fiber/c/include \ + -I$(ACL_PATH)/lib_fiber/cpp/include +EXTLIBS = +LDFLAGS = -L$(ACL_PATH)/lib_fiber/lib -lfiber_cpp \ + -L$(ACL_PATH)/lib_acl_cpp/lib -lacl_cpp \ + -L$(ACL_PATH)/lib_protocol/lib -lprotocol \ + -L$(ACL_PATH)/lib_acl/lib -lacl -lfiber \ + -lrocksdb -Wl,-rpath,/usr/local/lib \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = ./debug + +$(shell mkdir -p ${OBJ_PATH}) + +#Project's objs +SRC = $(wildcard *.cpp) $(wildcard db/*.cpp) \ + $(wildcard db/rocksdb/*.cpp) $(wildcard db/wt/*.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: db/%.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: db/rocksdb/%.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: db/wt/%.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/app/wizard_demo/pkv/action/redis_handler.cpp b/app/wizard_demo/pkv/action/redis_handler.cpp new file mode 100644 index 000000000..38453a192 --- /dev/null +++ b/app/wizard_demo/pkv/action/redis_handler.cpp @@ -0,0 +1,321 @@ +// +// Created by zsx on 2023/7/23. +// + +#include "stdafx.h" +#include "proto/redis_object.h" +#include "proto/redis_coder.h" +#include "redis_handler.h" + +namespace pkv { + +#define EQ !strcasecmp + +redis_handler::redis_handler(shared_db& db, const redis_coder& parser, + acl::socket_stream& conn) +: db_(db) +, parser_(parser) +, conn_(conn) +{ +} + +bool redis_handler::handle() { + auto objs = parser_.get_objects(); + if (objs.empty()) { + return true; + } + for (const auto& obj : objs) { + if (!handle_one(*obj)) { + return false; + } + } + + acl::string buf; + if (!builder_.to_string(buf)) { + return false; + } + return conn_.write(buf) != -1; +} + +bool redis_handler::handle_one(const redis_object &obj) { + auto cmd = obj.get_cmd(); + if (cmd == nullptr || *cmd == '\0') { + logger_error("redis command null"); + return false; + } + + //printf(">>>cmd=%s\r\n", cmd); + + if (EQ(cmd, "HSET")) { + return hset(obj); + } else if (EQ(cmd, "HGET")) { + return hget(obj); + } else if (EQ(cmd, "HDEL")) { + return hdel(obj); + } else if (EQ(cmd, "HMSET")) { + return hmset(obj); + } else if (EQ(cmd, "HMGET")) { + return hmget(obj); + } else if (EQ(cmd, "HGETALL")) { + return hgetall(obj); + } else if (EQ(cmd, "SET")) { + return set(obj); + } else if (EQ(cmd, "GET")) { + return get(obj); + } else if (EQ(cmd, "DEL")) { + return del(obj); + } else if (EQ(cmd, "TYPE")) { + return type(obj); + } + + acl::string err; + err.format("%s not support yet", cmd); + logger_error("cmd=%s not support!", cmd); + builder_.create_object().set_error(err); + return true; +} + +bool redis_handler::hset(const redis_object &obj) { + auto& objs = obj.get_objects(); + if (objs.size() < 4) { + logger_error("invalid HSET command's size=%zd < 4", objs.size()); + return false; + } + + auto key = objs[1]->get_str(); + if (key == nullptr || *key == 0) { + logger_error("key null"); + return false; + } + + auto name = objs[2]->get_str(); + if (name == nullptr || *name == 0) { + logger_error("name null"); + return false; + } + + auto value = objs[3]->get_str(); + if (value == nullptr || *value == 0) { + logger_error("value null"); + return false; + } + + redis_coder builder; + builder.create_object() + .create_child().set_string(name, true) + .create_child().set_string(value, true); + + acl::string buff; + if (!builder.to_string(buff)) { + logger_error("build data error"); + return false; + } + + if (!db_->set(key, buff.c_str())) { + logger_error("set key=%s, value=%s error", key, buff.c_str()); + return false; + } + + //printf(">set key=%s, value=%s ok\n", key, buff.c_str()); + builder_.create_object().set_number(1); + return true; +} + +bool redis_handler::hget(const redis_object &obj) { + auto& objs = obj.get_objects(); + if (objs.size() < 3) { + logger_error("invalid HGET command's size=%zd < 3", objs.size()); + return false; + } + + auto key = objs[1]->get_str(); + if (key == nullptr || *key == 0) { + logger_error("key null"); + return false; + } + + auto name = objs[2]->get_str(); + if (name == nullptr || *name == 0) { + logger_error("name null"); + return false; + } + + std::string buff; + if (!db_->get(key, buff) || buff.empty()) { + logger_error("db get key=%s error", key); + return false; + } + + //printf(">>hget: [%s]\r\n", buff.c_str()); + + redis_coder builder; + size_t len = buff.size(); + (void) builder.update(buff.c_str(), len); + if (len > 0) { + logger_error("invalid buff in db for key=%s", key); + return false; + } + + auto& objs2 = builder.get_objects(); + if (objs2.size() != 1) { + logger_error("invalid object in db, key=%s, objs=%zd", key, objs2.size()); + return false; + } + + auto array = objs2[0]; + if (array->get_type() != acl::REDIS_RESULT_ARRAY) { + logger_error("invalid array object, key=%s", key); + return false; + } + auto& objs3 = array->get_objects(); + if (objs3.empty() || objs3.size() % 2 != 0) { + logger_error("invalid array objects' size=%zd, key=%s", objs3.size(), key); + return false; + } + for (size_t i = 0; i < objs3.size();) { + auto n = objs3[i++]->get_str(); + auto v = objs3[i++]->get_str(); + if (n == nullptr || *n == 0 || v == nullptr || *v == 0) { + logger_error("no value set in db, key=%s", key); + return false; + } + if (strcmp(name, n) == 0) { + builder_.create_object().set_string(v); + return true; + } + } + + logger_error("Not found, key=%s, name=%s", key, name); + return false; +} + +bool redis_handler::hdel(const redis_object &obj) { + + return true; +} + +bool redis_handler::hmset(const redis_object &obj) { + + return true; +} + +bool redis_handler::hmget(const redis_object &obj) { + + return true; +} + +bool redis_handler::hgetall(const redis_object &obj) { + + return true; +} + +bool redis_handler::set(const redis_object &obj) { + auto& objs = obj.get_objects(); + if (objs.size() < 3) { + logger_error("invalid SET params' size=%zd", objs.size()); + return false; + } + + auto key = objs[1]->get_str(); + if (key == nullptr || *key == 0) { + logger_error("key null"); + return false; + } + + auto value = objs[2]->get_str(); + if (value == nullptr || *value == 0) { + logger_error("value null"); + return false; + } + + redis_coder builder; + builder.create_object().set_string(value); + + acl::string buff; + builder.to_string(buff); + + if (!db_->set(key, buff.c_str())) { + logger_error("db set error, key=%s", key); + return false; + } + + builder_.create_object().set_status("OK"); + return true; +} + +bool redis_handler::get(const redis_object &obj) { + auto& objs = obj.get_objects(); + if (objs.size() < 2) { + logger_error("invalid GET params' size=%zd", objs.size()); + return false; + } + + auto key = objs[1]->get_str(); + if (key == nullptr || *key == 0) { + logger_error("key null"); + return false; + } + + std::string buff; + if (!db_->get(key, buff) || buff.empty()) { + logger_error("db get error, key=%s", key); + return false; + } + + redis_coder builder; + size_t len = buff.size(); + (void) builder.update(buff.c_str(), len); + if (len > 0) { + logger_error("invalid buff in db, key=%s", key); + return false; + } + + auto& objs2 = builder.get_objects(); + if (objs2.size() != 1) { + logger_error("invalid object in db, key=%s, size=%zd", key, objs2.size()); + return false; + } + + auto o = objs2[0]; + if (o->get_type() != acl::REDIS_RESULT_STRING) { + logger_error("invalid object type=%d, key=%s", (int) o->get_type(), key); + return false; + } + + auto v = o->get_str(); + if (v == nullptr || *v == 0) { + logger_error("value null, key=%s", key); + return false; + } + builder_.create_object().set_string(v); + return true; +} + +bool redis_handler::del(const redis_object &obj) { + auto& objs = obj.get_objects(); + if (objs.size() < 2) { + logger_error("invalid SET params' size=%zd", objs.size()); + return false; + } + + auto key = objs[1]->get_str(); + if (key == nullptr || *key == 0) { + logger_error("key null"); + return false; + } + + if (!db_->del(key)) { + logger_error("db del error, key=%s", key); + return false; + } + + builder_.create_object().set_number(1); + return true; +} + +bool redis_handler::type(const redis_object &obj) { + builder_.create_object().set_status("string"); + return true; +} + +} // namespace pkv diff --git a/app/wizard_demo/pkv/action/redis_handler.h b/app/wizard_demo/pkv/action/redis_handler.h new file mode 100644 index 000000000..1a911817a --- /dev/null +++ b/app/wizard_demo/pkv/action/redis_handler.h @@ -0,0 +1,41 @@ +// +// Created by zsx on 2023/7/23. +// + +#pragma once + +#include "proto/redis_coder.h" +#include "db/db.h" + +namespace pkv { + +class redis_object; + +class redis_handler { +public: + explicit redis_handler(shared_db& db, const redis_coder& parser, + acl::socket_stream& conn); + ~redis_handler() = default; + + bool handle(); + +private: + shared_db& db_; + const redis_coder& parser_; + redis_coder builder_; + acl::socket_stream& conn_; + + bool handle_one(const redis_object& obj); + bool hset(const redis_object& obj); + bool hget(const redis_object& obj); + bool hdel(const redis_object& obj); + bool hmset(const redis_object& obj); + bool hmget(const redis_object& obj); + bool hgetall(const redis_object& obj); + bool set(const redis_object& obj); + bool get(const redis_object& obj); + bool del(const redis_object& obj); + bool type(const redis_object& obj); +}; + +} diff --git a/app/wizard_demo/pkv/dao/redis_hash.cpp b/app/wizard_demo/pkv/dao/redis_hash.cpp new file mode 100644 index 000000000..07f414d95 --- /dev/null +++ b/app/wizard_demo/pkv/dao/redis_hash.cpp @@ -0,0 +1,22 @@ +// +// Created by shuxin zheng on 2023/7/21. +// + +#include "stdafx.h" +#include "redis_hash.h" + +namespace pkv { + +redis_hash::redis_hash() {} + +redis_hash::~redis_hash() {} + +bool redis_hash::update(const char* cmd, const redis_object& obj) { + if (cmd == NULL || *cmd == 0) { + return false; + } + cmd_ = cmd; + return true; +} + +} // namespace pkv \ No newline at end of file diff --git a/app/wizard_demo/pkv/dao/redis_hash.h b/app/wizard_demo/pkv/dao/redis_hash.h new file mode 100644 index 000000000..1c4f6ce21 --- /dev/null +++ b/app/wizard_demo/pkv/dao/redis_hash.h @@ -0,0 +1,24 @@ +// +// Created by shuxin zheng on 2023/7/21. +// + +#pragma once + +namespace pkv { + +class redis_object; + +class redis_hash { +public: + redis_hash(); + ~redis_hash(); + + bool update(const char* cmd, const redis_object& obj); + +private: + std::string cmd_; + std::string key_; + std::map fields_; +}; + +} // namespace pkv \ No newline at end of file diff --git a/app/wizard_demo/pkv/db/db.cpp b/app/wizard_demo/pkv/db/db.cpp new file mode 100644 index 000000000..726150882 --- /dev/null +++ b/app/wizard_demo/pkv/db/db.cpp @@ -0,0 +1,37 @@ +#include "stdafx.h" +#include "rocksdb/rdb.h" +#include "db.h" + +namespace pkv { + +class dummy_db : public db { +public: + dummy_db() = default; + ~dummy_db() override = default; + + bool open(const char*) override { + return false; + } + + bool set(const std::string&, const std::string&) override { + return false; + } + + bool get(const std::string&, std::string&) override { + return false; + } + + bool del(const std::string&) override { + return false; + } +}; + +shared_db db::create_rdb() { +#ifdef HAS_ROCKSDB + return std::make_shared(); +#else + return std::make_shared(); +#endif +} + +} // namespace pkv diff --git a/app/wizard_demo/pkv/db/db.h b/app/wizard_demo/pkv/db/db.h new file mode 100644 index 000000000..694f798f1 --- /dev/null +++ b/app/wizard_demo/pkv/db/db.h @@ -0,0 +1,21 @@ +#pragma once + +namespace pkv { + +class db; +using shared_db = std::shared_ptr; + +class db { +public: + db() = default; + virtual ~db() = default; + + virtual bool open(const char* path) = 0; + virtual bool set(const std::string& key, const std::string& value) = 0; + virtual bool get(const std::string& key, std::string& value) = 0; + virtual bool del(const std::string& key) = 0; + + static shared_db create_rdb(); +}; + +} // namespace pkv diff --git a/app/wizard_demo/pkv/db/rocksdb/rdb.cpp b/app/wizard_demo/pkv/db/rocksdb/rdb.cpp new file mode 100644 index 000000000..5ce878689 --- /dev/null +++ b/app/wizard_demo/pkv/db/rocksdb/rdb.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" + +#ifdef HAS_ROCKSDB + +#include "rocksdb/db.h" +#include "rocksdb/slice.h" +#include "rocksdb/options.h" + +#include "rdb.h" + +using namespace rocksdb; + +namespace pkv { + +rdb::rdb() : db_(nullptr) {} + +rdb::~rdb() { + delete db_; +} + +bool rdb::open(const char* path) { + Options options; + options.IncreaseParallelism(); + // options.OptimizeLevelStyleCompaction(); + options.create_if_missing = true; + Status s = DB::Open(options, path, &db_); + if (!s.ok()) { + logger_error("open %s db error: %s", path, s.getState()); + return false; + } + + path_ = path; + return true; +} + +bool rdb::set(const std::string& key, const std::string& value) { + Status s = db_->Put(WriteOptions(), key, value); + if (!s.ok()) { + logger_error("put to %s error: %s, key=%s", + path_.c_str(), s.getState(), key.c_str()); + return false; + } + + return true; +} + +bool rdb::get(const std::string& key, std::string& value) { + Status s = db_->Get(ReadOptions(), key, &value); + if (!s.ok()) { + logger_error("get from %s error: %s, key=%s, data=%zd", + path_.c_str(), s.getState(), key.c_str(), value.size()); + return false; + } + + return true; +} + +bool rdb::del(const std::string& key) { + Status s = db_->Delete(WriteOptions(), key); + if (!s.ok()) { + logger_error("del from %s error: %s", path_.c_str(), s.getState()); + return false; + } + + return true; +} + +} // namespace pkv + +#endif // HAS_ROCKSDB diff --git a/app/wizard_demo/pkv/db/rocksdb/rdb.h b/app/wizard_demo/pkv/db/rocksdb/rdb.h new file mode 100644 index 000000000..f69be4008 --- /dev/null +++ b/app/wizard_demo/pkv/db/rocksdb/rdb.h @@ -0,0 +1,38 @@ +#pragma once + +#include "db/db.h" + +#ifdef HAS_ROCKSDB + +namespace rocksdb { + class DB; +} + +namespace pkv { + +class rdb : public db { +public: + rdb(); + ~rdb() override; + +protected: + // @override + bool open(const char* path) override; + + // @override + bool set(const std::string& key, const std::string& value) override; + + // @override + bool get(const std::string& key, std::string& value) override; + + // @override + bool del(const std::string& key) override; + +private: + std::string path_; + rocksdb::DB* db_; +}; + +} // namespace pkv + +#endif // HAS_ROCKSDB diff --git a/app/wizard_demo/pkv/hash.txt b/app/wizard_demo/pkv/hash.txt new file mode 100644 index 000000000..9ac6316bc --- /dev/null +++ b/app/wizard_demo/pkv/hash.txt @@ -0,0 +1,17 @@ +*8 +$5 +HMSET +$8 +hash-key +$6 +field1 +$6 +vaule1 +$6 +field2 +$6 +vaule2 +$6 +field3 +$6 +vaule3 diff --git a/app/wizard_demo/pkv/main.cpp b/app/wizard_demo/pkv/main.cpp new file mode 100644 index 000000000..e024f9a03 --- /dev/null +++ b/app/wizard_demo/pkv/main.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "proto/redis_coder.h" +#include "master_service.h" + +static bool test_redis_coder(const char* file) { +#if 1 + printf(">>>>>>>>Begin to test redis parsing<<<<<<<<<\r\n"); + if (!pkv::test_redis_parse(file)) { + printf(">>>>>>>Test redis parsing Error<<<<<<<\r\n"); + return false; + } + printf(">>>>>>>Test redis parsing successfully<<<<<<<<<\r\n"); +#endif + + printf("\r\n"); + + printf(">>>>>>>>>Begin to test redis building<<<<<<<<\r\n"); + if (!pkv::test_redis_build()) { + printf(">>>>>Test redis building Error<<<<<<<<\r\n"); + return false; + } + printf(">>>>>>>Test redis building successfully<<<<<<<\r\n"); + + return true; +} + +int main(int argc, char *argv[]) { + acl::acl_cpp_init(); + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + if (argc >= 2 && strcasecmp(argv[1], "test") == 0) { + const char* file = "hash.txt"; + if (argc >= 3) { + file = argv[2]; + } + test_redis_coder(file); + return 0; + } else if (argc == 1 || (argc >= 2 && strcasecmp(argv[1], "alone") == 0)) { + // 日志输出至标准输出 + acl::log::stdout_open(true); + // 禁止生成 acl_master.log 日志 + acl::master_log_enable(false); + + const char* addr = nullptr; + printf("listen: %s\r\n", addr); + ms.run_alone(addr, argc >= 3 ? argv[2] : nullptr); + } else { +#if defined(_WIN32) || defined(_WIN64) + const char* addr = "|8887"; + + acl::log::stdout_open(true); + printf("listen on: %s\r\n", addrs); + ms.run_alone(addr, argc >= 3 ? argv[2] : NULL); +#else + ms.run_daemon(argc, argv); +#endif + } + + return 0; +} diff --git a/app/wizard_demo/pkv/master_service.cpp b/app/wizard_demo/pkv/master_service.cpp new file mode 100644 index 000000000..c73514f55 --- /dev/null +++ b/app/wizard_demo/pkv/master_service.cpp @@ -0,0 +1,99 @@ +#include "stdafx.h" +#include "proto/redis_coder.h" +#include "action/redis_handler.h" +#include "master_service.h" + +static char *var_cfg_dbpath; + +acl::master_str_tbl var_conf_str_tab[] = { + { "dbpath", "./dbpath", &var_cfg_dbpath }, + + { 0, 0, 0 } +}; + +static int var_cfg_debug_enable; + +acl::master_bool_tbl var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + + { 0, 0, 0 } +}; + +static int var_cfg_io_timeout; + +acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +acl::master_int64_tbl var_conf_int64_tab[] = { + { 0, 0 , 0 , 0, 0 } +}; + + +////////////////////////////////////////////////////////////////////////// + +using namespace pkv; + +void master_service::on_accept(acl::socket_stream& conn) { + //logger(">>>accept connection: %d", conn.sock_handle()); + //conn.set_rw_timeout(var_cfg_io_timeout); + + pkv::redis_coder parser; + char buf[8192]; + size_t n = sizeof(buf) - 1; + + while(true) { + int ret = conn.read(buf, sizeof(n) - 1, false); + if (ret <= 0) { + break; + } + buf[ret] = 0; + //printf("[%s]\r\n", buf); + + size_t len = (size_t) ret; + const char* data = parser.update(buf, len); + auto obj = parser.get_curr(); + assert(obj); + if (obj->failed()) { + break; + } + + //printf("len=%zd, data=%s\r\n", len, data); + assert(*data == '\0' && len == 0); + + pkv::redis_handler handler(db_, parser, conn); + if (!handler.handle()) { + break; + } + + parser.clear(); + } +} + +void master_service::proc_pre_jail() { + logger(">>>proc_pre_jail<<<"); +} + +void master_service::proc_on_listen(acl::server_socket& ss) { + logger(">>>listen %s ok<<<", ss.get_addr()); +} + +void master_service::proc_on_init() { + logger(">>>proc_on_init<<<"); + db_ = db::create_rdb(); + if (!db_->open(var_cfg_dbpath)) { + logger_error("open db(%s) error %s", var_cfg_dbpath, acl::last_serror()); + exit(1); + } +} + +void master_service::proc_on_exit() { + logger(">>>proc_on_exit<<<"); +} + +bool master_service::proc_on_sighup(acl::string&) { + logger(">>>proc_on_sighup<<<"); + return true; +} diff --git a/app/wizard_demo/pkv/master_service.h b/app/wizard_demo/pkv/master_service.h new file mode 100644 index 000000000..8e802feb9 --- /dev/null +++ b/app/wizard_demo/pkv/master_service.h @@ -0,0 +1,31 @@ +#pragma once + +#include "db/db.h" + +class master_service : public acl::master_fiber { +public: + master_service() = default; + ~master_service() override = default; + +protected: + // @override + void on_accept(acl::socket_stream& conn) override; + + // @override + void proc_on_listen(acl::server_socket& ss) override; + + // @override + void proc_pre_jail() override; + + // @override + void proc_on_init() override; + + // @override + void proc_on_exit() override; + + // @override + bool proc_on_sighup(acl::string&) override; + +private: + pkv::shared_db db_; +}; diff --git a/app/wizard_demo/pkv/pkv.cf b/app/wizard_demo/pkv/pkv.cf new file mode 100644 index 000000000..544e8ee57 --- /dev/null +++ b/app/wizard_demo/pkv/pkv.cf @@ -0,0 +1,147 @@ + +service pkv +{ +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# for master_type = inet +# master_service = 127.0.0.1|5001 +# for master_type = unix +# master_service = echo.sock +# for master_type = sock + master_service = 127.0.0.1|5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 停止子进程时是否采用强行停止的方式(即给子进程发送 SIGTERM 信号) + master_stop_kill = false +# 当 master_stop_kill 为 true 时,该配置决定是否要等待子进程退出 + master_stop_wait = false + +# 当系统支持 SO_REUSEPORT 时,是否启用该功能 + master_reuseport = yes +# 当启用 SO_REUSEPORT 时(即 master_reuseport=yes 时), 是否需要 acl_master +# 也监听该地址, 对于使用旧版 acl(< 3.5.3-17) 编写的服务, 必须将此项设为 +# yes, 即: master_reuseport_listen = yes; 对于使用 acl 版本 >= 3.5.3-17 +# 编写的服务需设置为 no; 当 master_reuseport=no时,该项设置将被忽略; 当未 +# 设置此项时内部缺省值为 yes. 以便使 acl_master 保持对于旧版服务的兼容性. + master_reuseport_listen = no +# 是否针对监听套接口设定为非阻塞方式 + master_nonblock = yes +# 当系统支持 TCP_FASTOPEN 时,是否启用该功能 + master_fastopen = no + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 预启动进程数,该值不得大于 master_maxproc + master_prefork = 1 +# 进程程序名 + master_command = {install_path}/sbin/pkv +# 进程日志记录文件 + master_log = {install_path}/var/log/pkv.log +# 调试日志方式,格式:tag:level; tag:level; tab:level, 如:all:1; 101:2 +# master_debug = +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# 当启动多个子进程实例时,该开关控制多个子进程在接收连接时是否向 acl_master 发送消息报告自己的状态 +# master_status_notify = 1 +# 程序标准输出重定向至指定文件中 +# master_stdout = {install_path}/var/log/stdout.log +# 程序错误输出重定向至指定文件中 +# master_stderr = {install_path}/var/log/stderr.log + +# 事件引擎: kernel, poll, select, io_uring + fiber_schedule_event = kernel +# fiber_schedule_event = io_uring +# 是否允许产生 core 文件 +# fiber_enable_core = 1 +# core 文件大小限制,-1 表示不限制 core 文件大小,0 表示禁止产生 core,> 0 表示 core 文件最大大小 +# fiber_core_limit = -1 +# 进程退出时是否禁止产生 core 文件 +# fiber_disable_core_onexit = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + fiber_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + fiber_idle_limit = 0 +# 每个进程启动的线程数 + fiber_threads = 8 +# 进程运行时所在的路径 + fiber_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + fiber_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + fiber_buf_size = 8192 +# 进程运行时的用户身份 + fiber_owner = root + +# 当启用 master_dispatch 连接分开服务后,该配置指定 master_dispatch 所监听的 +# 域套接口的全路径,这样本子进程就可以从 master_dispatch 获得客户端连接 +# fiber_dispatch_addr = {install_path}/var/private/dispatch.sock +# 当 fiber_dispatch_addr 开启后,下面参数控制本服务进程发给前端 master_dispatch 的服务标识信息 +# fiber_dispatch_type = default + +# 线程的堆栈空间大小,单位为字节 + fiber_stack_size = 64000 +# 允许访问 udserver 的客户端IP地址范围 +# fiber_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + fiber_access_allow = all + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + fiber_quick_abort = 1 + +# 是否启用协程共享栈模式 + fiber_share_stack = 0 + +# 当 fiber_quick_abort 为 0 且本配置项大于 0 时,该配置项才有效,指定了 +# 本进程在所有连接退出前的最大等待时间(秒) + fiber_wait_limit = 0 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = fiber_db +# 数据库访问用户 +# mysql_dbuser = fiber_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 +# debug_mem = 1 +# 是否在一个线程中连接读 +# loop_read = 1 +} diff --git a/app/wizard_demo/pkv/pkv.sln b/app/wizard_demo/pkv/pkv.sln new file mode 100644 index 000000000..33327fa9e --- /dev/null +++ b/app/wizard_demo/pkv/pkv.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkv", "pkv.vcproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + ReleaseDll = ReleaseDll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/wizard_demo/pkv/pkv_vc2019.sln b/app/wizard_demo/pkv/pkv_vc2019.sln new file mode 100644 index 000000000..92932fccb --- /dev/null +++ b/app/wizard_demo/pkv/pkv_vc2019.sln @@ -0,0 +1,37 @@ +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 2019 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkv", "pkv_vc2019.vcxproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + DebugDll|Win32 = DebugDll|Win32 + DebugDll|x64 = DebugDll|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseDll|Win32 = ReleaseDll|Win32 + ReleaseDll|x64 = ReleaseDll|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|x64.ActiveCfg = Debug|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|x64.Build.0 = Debug|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|x64.ActiveCfg = DebugDll|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|x64.Build.0 = DebugDll|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|x64.ActiveCfg = Release|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|x64.Build.0 = Release|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|x64.ActiveCfg = ReleaseDll|x64 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|x64.Build.0 = ReleaseDll|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/wizard_demo/pkv/pkv_vc2019.vcxproj b/app/wizard_demo/pkv/pkv_vc2019.vcxproj new file mode 100644 index 000000000..d86e1764e --- /dev/null +++ b/app/wizard_demo/pkv/pkv_vc2019.vcxproj @@ -0,0 +1,356 @@ + + + + + DebugDll + Win32 + + + DebugDll + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDll + Win32 + + + ReleaseDll + x64 + + + Release + Win32 + + + Release + x64 + + + + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C} + Win32Proj + pkv + 10.0 + + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + .\ + Debug\ + true + + + true + .\ + Debug\ + + + Release\ + Release\ + false + + + false + .\ + Release\ + + + .\ + ReleaseDll\ + false + + + false + .\ + ReleaseDll\ + + + .\ + DebugDll\ + true + + + true + .\ + DebugDll\ + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)pkv.pdb + Console + MachineX86 + false + + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + $(OutDir)pkv.pdb + Console + false + 20240000 + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + copy $(OutDir)\..\..\..\$(Configuration)\lib_acl.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_acl_cpp.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_protocol.dll $(OutDir) /Y + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + Console + true + true + + + copy $(OutDir)\..\..\..\$(Configuration)\lib_acl.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_acl_cpp.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_protocol.dll $(OutDir) /Y + + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)pkv.pdb + Console + MachineX86 + + + copy $(OutDir)\..\..\..\$(Configuration)\lib_acl.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_acl_cpp.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_protocol.dll $(OutDir) /Y + + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;lib_acl.lib;lib_protocol.lib;libfiber.lib;libfiber_cpp.lib;%(AdditionalDependencies) + $(OutDir)pkv.exe + ..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + $(OutDir)pkv.pdb + Console + + + copy $(OutDir)\..\..\..\$(Configuration)\lib_acl.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_acl_cpp.dll $(OutDir) /Y copy $(OutDir)\..\..\..\$(Configuration)\lib_protocol.dll $(OutDir) /Y + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + diff --git a/app/wizard_demo/pkv/pkv_vc2019.vcxproj.filters b/app/wizard_demo/pkv/pkv_vc2019.vcxproj.filters new file mode 100644 index 000000000..7123095d1 --- /dev/null +++ b/app/wizard_demo/pkv/pkv_vc2019.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + + + + diff --git a/app/wizard_demo/pkv/proto/redis_coder.cpp b/app/wizard_demo/pkv/proto/redis_coder.cpp new file mode 100644 index 000000000..b90e1ca74 --- /dev/null +++ b/app/wizard_demo/pkv/proto/redis_coder.cpp @@ -0,0 +1,198 @@ +// +// Created by shuxin zheng on 2023/7/19. +// + +#include "stdafx.h" +#include "redis_coder.h" + +namespace pkv { + +redis_coder::redis_coder() { + curr_ = std::make_shared(nullptr); +} + +void redis_coder::clear() { + objs_.clear(); +} + +const char* redis_coder::update(const char* data, size_t& len) { + while (len > 0) { + data = curr_->update(data, len); + if (curr_->finish()) { + objs_.push_back(curr_); + curr_ = std::make_shared(nullptr); + } else if (curr_->failed()) { + break; + } + } + + return data; +} + +redis_object& redis_coder::create_object() { + auto obj = std::make_shared(nullptr); + objs_.emplace_back(obj); + return *obj; +} + +bool redis_coder::to_string(acl::string& out) const { + for (const auto& obj : objs_) { + if (!obj->to_string(out)) { + return false; + } + } + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +bool test_redis_parse(const char* filepath) { + if (!test_redis_parse_once(filepath)) { + return false; + } + + printf("\r\n"); + + if (!test_redis_parse_stream(filepath)) { + return false; + } + + return true; +} + +bool test_redis_parse_once(const char* filepath) { + acl::string buf; + if (!acl::ifstream::load(filepath, buf)) { + printf("load %s error %s\r\n", filepath, acl::last_serror()); + return false; + } + + redis_coder parser; + const char* data = buf.c_str(); + size_t len = buf.size(); + const char* left = parser.update(data, len); + + if (len > 0) { + printf(">>>%s: parse failed<<<\r\n", __func__); + printf("%s\r\n", left); + return false; + } + + printf(">>>%s: parse success<<<\r\n", __func__); + + acl::string out; + + if (!parser.to_string(out)) { + printf(">>>%s: build failed<<<\r\n", __func__); + return false; + } + + if (out != buf) { + printf(">>>%s: build failed<<<\r\n", __func__); + printf("output:\r\n|%s|\r\n", out.c_str()); + printf("input:\r\n|%s|\r\n", buf.c_str()); + + acl::string filetmp(filepath); + filetmp += ".tmp"; + acl::ofstream fp; + if (fp.open_trunc(filetmp)) { + fp.write(out); + } + + return false; + } + + printf("%s\r\n", out.c_str()); + printf(">>>%s: build successfully<<<\r\n", __func__); + return true; +} + +bool test_redis_parse_stream(const char* filepath) { + acl::string buf; + + if (!acl::ifstream::load(filepath, buf)) { + printf("load %s error %s\r\n", filepath, acl::last_serror()); + return false; + } + + redis_coder parser; + const char* data = buf.c_str(); + size_t len = buf.size(); + for (size_t i = 0; i < len; i++) { + char ch = *data++; + size_t n = 1; + //putchar(ch); + const char* left = parser.update(&ch, n); + if (n > 0) { + printf(">>>%s(%d): parse failed, left=%s<<<\r\n", __func__, __LINE__, left); + return false; + } + } + printf(">>%s(%d): parse successfully<<<\r\n", __func__, __LINE__); + + acl::string out; + + if (!parser.to_string(out)) { + printf(">>%s(%d): build failed<<\r\n", __func__, __LINE__); + return false; + } + + if (out != buf) { + printf("%s\r\n", out.c_str()); + printf(">>%s(%d): build failed<<\r\n", __func__, __LINE__); + return false; + } + + printf("%s\r\n", out.c_str()); + const char* cmd = parser.get_objects()[0]->get_cmd(); + printf(">>%s(%d): build successfully, cmd=%s<<\r\n", + __func__, __LINE__, cmd ? cmd : "unknown"); + return true; +} + +////////////////////////////////////////////////////////////////////////////// + +bool test_redis_build() { + redis_coder builder; + + auto& obj = builder.create_object(); + +#if 0 + obj.create_child().set_string("HMSET"); + obj.create_child().set_string("hash-key"); + obj.create_child().set_string("field1"); + obj.create_child().set_string("vaule1"); + obj.create_child().set_string("field2"); + obj.create_child().set_string("value2"); + obj.create_child().set_string("field3"); + obj.create_child().set_string("value3"); +#else + obj.create_child().set_string("HMSET", true) + .create_child().set_string("hash-key", true) + .create_child().set_string("field1", true) + .create_child().set_string("value1", true) + .create_child().set_string("field2", true) + .create_child().set_string("value2", true) + .create_child().set_string("field3", true) + .create_child().set_string("value3", true); +#endif + + acl::string buf; + if (builder.to_string(buf)) { + const char* cmd = obj.get_cmd(); + printf("%s(%d): build redis successfully, cmd=%s\r\n", + __func__, __LINE__, cmd ? cmd : "unknown"); + printf("[%s]\r\n", buf.c_str()); + } else { + printf("%s(%d): build redis failed\r\n", __func__, __LINE__); + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +} // namespace pkv \ No newline at end of file diff --git a/app/wizard_demo/pkv/proto/redis_coder.h b/app/wizard_demo/pkv/proto/redis_coder.h new file mode 100644 index 000000000..290ae4c57 --- /dev/null +++ b/app/wizard_demo/pkv/proto/redis_coder.h @@ -0,0 +1,44 @@ +// +// Created by shuxin zheng on 2023/7/19. +// + +#pragma once + +#include "redis_object.h" + +namespace pkv { + +class redis_coder { +public: + redis_coder(); + ~redis_coder() = default; + + const char* update(const char* data, size_t& len); + + [[nodiscard]] const std::vector& get_objects() const { + return objs_; + } + + [[nodiscard]] shared_redis get_curr() const { + return curr_; + } + + void clear(); + +public: + [[nodiscard]] redis_object& create_object(); + + bool to_string(acl::string& out) const; + +private: + std::vector objs_; + shared_redis curr_; +}; + +bool test_redis_parse(const char* filepath); +bool test_redis_parse_once(const char* filepath); +bool test_redis_parse_stream(const char* filepath); + +bool test_redis_build(); + +} // namespace pkv diff --git a/app/wizard_demo/pkv/proto/redis_object.cpp b/app/wizard_demo/pkv/proto/redis_object.cpp new file mode 100644 index 000000000..9b7a9deb7 --- /dev/null +++ b/app/wizard_demo/pkv/proto/redis_object.cpp @@ -0,0 +1,464 @@ +// +// Created by shuxin zheng on 2023/7/19. +// + +#include "stdafx.h" +#include "redis_object.h" + +namespace pkv { + +redis_object::redis_object(redis_object* parent) { + dbuf_ = new (1) acl::dbuf_pool(); + parent_ = parent ? parent : this; +} + +redis_object::~redis_object() { + dbuf_->destroy(); +} + +const char* redis_object::get_cmd() const { + if (me_ == nullptr) { + return nullptr; + } + + if (me_->get_type() == acl::REDIS_RESULT_STRING) { + return me_->get(0); + } + + if (objs_.empty() || me_->get_type() != acl::REDIS_RESULT_ARRAY) { + return nullptr; + } + + return objs_[0]->get_cmd(); +} + +const char* redis_object::get_str() const { + if (me_->get_type() == acl::REDIS_RESULT_STRING) { + return me_->get(0); + } + + return nullptr; +} + +struct status_machine { + /* ״̬ */ + int status; + + /* ״̬ */ + const char* (redis_object::*func) (const char*, size_t&); +}; + +static struct status_machine status_tab[] = { + { redis_s_begin, &redis_object::parse_begin }, + { redis_s_status, &redis_object::parse_status }, + { redis_s_error, &redis_object::parse_error }, + { redis_s_number, &redis_object::parse_number }, + { redis_s_strlen, &redis_object::parse_strlen }, + { redis_s_string, &redis_object::parse_string }, + { redis_s_strend, &redis_object::parse_strend }, + { redis_s_arlen, &redis_object::parse_arlen }, + { redis_s_array, &redis_object::parse_array }, +}; + +const char* redis_object::update(const char *data, size_t& len) { + if (failed() || finish()) { + return data; + } + + if (obj_) { + return parse_object(data, len); + } + + while (len > 0) { + data = (this->*(status_tab[status_].func))(data, len); + if (status_ == redis_s_null || status_ == redis_s_finish) { + break; + } + } + + return data; +} + +const char* redis_object::parse_object(const char* data, size_t& len) { + assert(cnt_ > 0); + assert(obj_); + + data = obj_->update(data, len); + if (obj_->failed()) { + status_ = redis_s_null; + return data; + } + + if (!obj_->finish()) { + return data; + } + + objs_.emplace_back(obj_); + + if (objs_.size() == (size_t) cnt_) { + obj_ = nullptr; + cnt_ = 0; + status_ = redis_s_finish; + } else { + obj_ = std::make_shared(this); + } + return data; +} + +const char* redis_object::parse_begin(const char* data, size_t& len) { + if (len == 0) { + return data; + } + + switch (*data) { + case ':': // INTEGER + status_ = redis_s_number; + break; + case '+': // STATUS + status_ = redis_s_status; + break; + case '-': // ERROR + status_ = redis_s_error; + break; + case '$': // STRING + status_ = redis_s_strlen; + break; + case '*': // ARRAY + status_ = redis_s_arlen; + break; + default: // INVALID + status_ = redis_s_null; + break; + } + + len--; + data++; + return data; +} + +const char* redis_object::parse_status(const char* data, size_t& len) { + bool found = false; + data = get_line(data, len, found); + if (!found) { + assert(len == 0); + return data; + } + + if (buf_.empty()) { + status_ = redis_s_null; + return data; + } + + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_STATUS); + me_->set_size(1); + put_data(dbuf_, me_, buf_.c_str(), buf_.length()); + buf_.clear(); + + status_ = redis_s_finish; + return data; +} + +const char* redis_object::parse_error(const char* data, size_t& len) { + bool found = false; + data = get_line(data, len, found); + if (!found) { + assert(len == 0); + return data; + } + + if (buf_.empty()) { + status_ = redis_s_null; + return data; + } + + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_ERROR); + me_->set_size(1); + put_data(dbuf_, me_, buf_.c_str(), buf_.length()); + buf_.clear(); + + status_ = redis_s_finish; + return data; +} + +const char* redis_object::parse_number(const char* data, size_t& len) { + bool found = false; + data = get_line(data, len, found); + if (!found) { + assert(len == 0); + return data; + } + + if (buf_.empty()) { + status_ = redis_s_null; + return data; + } + + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_INTEGER); + me_->set_size(1); + put_data(dbuf_, me_, buf_.c_str(), buf_.length()); + buf_.clear(); + + status_ = redis_s_finish; + return data; +} + +const char* redis_object::parse_strlen(const char* data, size_t& len) { + bool found = false; + cnt_ = 0; + data = get_length(data, len, cnt_, found); + if (status_ == redis_s_null || !found) { + return data; + } + + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_STRING); + + if (cnt_ <= 0) { + status_ = redis_s_finish; + return data; + } + + me_->set_size((size_t) cnt_); + buf_.clear(); + + status_ = redis_s_string; + return data; +} + +const char* redis_object::parse_string(const char* data, size_t& len) { + assert (me_ != nullptr); + + data = get_data(data, len, (size_t) cnt_); + if (buf_.size() == (size_t) cnt_) { + status_ = redis_s_strend; + put_data(dbuf_, me_, buf_.c_str(), buf_.length()); + buf_.clear(); + cnt_ = 0; + } + + return data; +} + +const char* redis_object::parse_strend(const char* data, size_t& len) { + assert (me_ != nullptr); + + bool found = false; + data = get_line(data, len, found); + + // If the buf_ not empty, some data other '\r\n' got. + if (!buf_.empty()) { + status_ = redis_s_null; + return data; + } + + if (!found) { + assert(len == 0); + return data; + } + + status_ = redis_s_finish; + return data; +} + +const char* redis_object::parse_arlen(const char* data, size_t& len) { + bool found = false; + cnt_ = 0; + data = get_length(data, len, cnt_, found); + if (status_ == redis_s_null || !found) { + return data; + } + + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_ARRAY); + + if (cnt_ <= 0) { + status_ = redis_s_finish; + return data; + } + + me_->set_size((size_t) cnt_); + + buf_.clear(); + status_ = redis_s_array; + obj_ = std::make_shared(this); + return data; +} + +const char* redis_object::parse_array(const char* data, size_t& len) { + assert(me_ != nullptr); + assert(obj_ != nullptr); + + return parse_object(data, len); +} + +const char* redis_object::get_data(const char* data, size_t& len, size_t want) { + size_t n = buf_.size(); + assert(n < want); + + want -= n; + for (size_t i = 0; i < want && len > 0; i++) { + buf_.push_back(*data++); + len--; + } + return data; +} + +const char* redis_object::get_length(const char* data, size_t& len, + int& res, bool& found) { + data = get_line(data, len, found); + if (!found) { + assert(len == 0); + return data; + } + + if (buf_.empty()) { + status_ = redis_s_null; + return data; + } + + // buf_.push_back('\0'); // The c++11 promise the last char is null. + char* endptr; + res = (int) strtol(buf_.c_str(), &endptr, 10); + buf_.clear(); + + if (endptr == buf_.c_str() || *endptr != '\0') { + status_ = redis_s_null; + return data; + } + return data; +} + +const char* redis_object::get_line(const char* data, size_t& len, bool& found) { + while (len > 0) { + switch (*data) { + case '\r': + data++; + len--; + break; + case '\n': + data++; + len--; + found = true; + return data; + default: + buf_.push_back(*data++); + len--; + break; + } + } + return data; +} + +void redis_object::put_data(acl::dbuf_pool* dbuf, acl::redis_result* rr, + const char* data, size_t len) { + char* buf = (char*) dbuf->dbuf_alloc(len + 1); + if (len > 0) { + memcpy(buf, data, len); + } + + buf[len] = 0; + rr->put(buf, len); +} + +bool redis_object::to_string(acl::string& out) const { +#define USE_UNIX_CRLF +#ifdef USE_UNIX_CRLF +#define CRLF "\n" +#else +#define CRLF "\r\n" +#endif + + if (!objs_.empty()) { + out.format_append("*%zd%s", objs_.size(), CRLF); + + for (const auto& obj : objs_) { + if (!obj->to_string(out)) { + return false; + } + } + } + + if (me_ == nullptr) { + return false; + } + + switch (me_->get_type()) { + case acl::REDIS_RESULT_STATUS: + out.format_append("+%s%s", me_->get_status(), CRLF); + break; + case acl::REDIS_RESULT_ERROR: + out.format_append("-%s%s", me_->get_error(), CRLF); + break; + case acl::REDIS_RESULT_INTEGER: + out.format_append(":%lld%s", me_->get_integer64(), CRLF); + break; + case acl::REDIS_RESULT_STRING: + out.format_append("$%zd%s", me_->get_length(), CRLF); + me_->argv_to_string(out, false); + out += CRLF; + break; + //case acl::REDIS_RESULT_ARRAY: + // break; + default: + break; + } + return true; +} + +redis_object& redis_object::set_status(const std::string& data, + bool return_parent) { + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_STATUS); + me_->set_size(1); + put_data(dbuf_, me_, data.c_str(), data.length()); + return return_parent ? *parent_ : *this; +} + +redis_object& redis_object::set_error(const std::string& data, + bool return_parent) { + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_ERROR); + me_->set_size(1); + put_data(dbuf_, me_, data.c_str(), data.length()); + return return_parent ? *parent_ : *this; +} + +redis_object& redis_object::set_number(int n, bool return_parent) { + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_INTEGER); + me_->set_size(1); + + std::string buf = std::to_string(n); + put_data(dbuf_, me_, buf.c_str(), buf.length()); + return return_parent ? *parent_ : *this; +} + +redis_object& redis_object::set_string(const std::string &data, + bool return_parent) { + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_STRING); + me_->set_size(data.size()); + if (!data.empty()) { + put_data(dbuf_, me_, data.c_str(), data.length()); + } + return return_parent ? *parent_ : *this; +} + +redis_object& redis_object::create_child() { + auto obj = std::make_shared(this); + objs_.emplace_back(obj); + + if (me_ == nullptr) { + // The last one is NULL. + me_ = new(dbuf_) acl::redis_result(dbuf_); + me_->set_type(acl::REDIS_RESULT_ARRAY); + } + + me_->set_size(objs_.size()); + return *obj; +} + +} // namespace pkv diff --git a/app/wizard_demo/pkv/proto/redis_object.h b/app/wizard_demo/pkv/proto/redis_object.h new file mode 100644 index 000000000..894db1432 --- /dev/null +++ b/app/wizard_demo/pkv/proto/redis_object.h @@ -0,0 +1,89 @@ +// +// Created by shuxin zheng on 2023/7/19. +// + +#pragma once + +#include "redis_type.h" + +namespace pkv { + +class redis_object; +using shared_redis = std::shared_ptr; + +class redis_object { +public: + explicit redis_object(redis_object* parent); + ~redis_object(); + + redis_object(const redis_object&) = delete; + void operator=(const redis_object&) = delete; + +public: + const char* update(const char* data, size_t& len); + + [[nodiscard]] bool finish() const { + return status_ == redis_s_finish; + } + + [[nodiscard]] bool failed() const { + return status_ == redis_s_null; + } + + [[nodiscard]] int get_status() const { + return status_; + } + + [[nodiscard]] acl::redis_result_t get_type() const { + return me_ ? me_->get_type() : acl::REDIS_RESULT_UNKOWN; + } + + [[nodiscard]] const char* get_cmd() const; + + [[nodiscard]] const char* get_str() const; + + [[nodiscard]] const std::vector& get_objects() const { + return objs_; + } + +public: + redis_object& set_status(const std::string& data, bool return_parent = false); + redis_object& set_error(const std::string& data, bool return_parent = false); + redis_object& set_number(int n, bool return_parent = false); + redis_object& set_string(const std::string& data, bool return_parent = false); + redis_object& create_child(); + + bool to_string(acl::string& out) const; + +private: + acl::dbuf_pool* dbuf_; + redis_object* parent_; + int status_ = redis_s_begin; + acl::redis_result* me_ = nullptr; + std::vector objs_; + + std::string buf_; + int cnt_ = 0; + shared_redis obj_ = nullptr; + +private: + static void put_data(acl::dbuf_pool*, acl::redis_result*, const char*, size_t); + const char* get_line(const char*, size_t&, bool&); + const char* get_length(const char*, size_t&, int&, bool&); + const char* get_data(const char*, size_t&, size_t); + + const char* parse_object(const char*, size_t&); + +public: + const char* parse_begin(const char* data, size_t& len); + const char* parse_status(const char* data, size_t& len); + const char* parse_error(const char* data, size_t& len); + const char* parse_number(const char* data, size_t& len); + const char* parse_strlen(const char* data, size_t& len); + const char* parse_string(const char* data, size_t& len); + const char* parse_strend(const char* data, size_t& len); + const char* parse_arlen(const char* data, size_t& len); + const char* parse_array(const char* data, size_t& len); +}; + +} // namespace pkv diff --git a/app/wizard_demo/pkv/proto/redis_type.h b/app/wizard_demo/pkv/proto/redis_type.h new file mode 100644 index 000000000..c2d169c20 --- /dev/null +++ b/app/wizard_demo/pkv/proto/redis_type.h @@ -0,0 +1,23 @@ +// +// Created by shuxin zheng on 2023/7/19. +// + +#pragma once + +namespace pkv { + +enum { + redis_s_begin, + redis_s_status, + redis_s_error, + redis_s_number, + redis_s_strlen, + redis_s_string, + redis_s_strend, + redis_s_arlen, + redis_s_array, + redis_s_null, + redis_s_finish, +}; + +} // namespace pkv diff --git a/app/wizard_demo/pkv/setup.sh b/app/wizard_demo/pkv/setup.sh new file mode 100755 index 000000000..50c0d4451 --- /dev/null +++ b/app/wizard_demo/pkv/setup.sh @@ -0,0 +1,197 @@ +#!/bin/sh + +############################################################################### +PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc +tempdir="/tmp" + +umask 022 + +function censored_ls() { + ls "$@" | egrep -v '^\.|/\.|CVS|RCS|SCCS|linux\.d|solaris\.d|hp_ux\.d|example' +} + +function compare_or_replace() { + (cmp $2 $3 >/dev/null 2>&1 && echo Skipping $3...) || { + echo Updating $3... + rm -f $tempdir/junk || exit 1 + cp $2 $tempdir/junk || exit 1 + chmod $1 $tempdir/junk || exit 1 + mv -f $tempdir/junk $3 || exit 1 + chmod $1 $3 || exit 1 + } +} +############################################################################### +RPATH= +function guess_os() { + os_name=`uname -s` + os_type=`uname -p` + case $os_name in + Linux) + case $os_type in + x86_64) + RPATH="linux64" + ;; + i686) + RPATH="linux32" + ;; + aarch64) + RPATH="aarch64" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + SunOS) + case $os_type in + i386) + RPATH="sunos_x86" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + FreeBSD) + RPATH="freebsd" + ;; + Darwin) + RPATH="macos" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac +} + +function create_path() { + test -d $1 || mkdir -p $1 || { + echo "can't mkdir $1" + exit 1 + } +} + +function copy_file() { + test -f $2 && { + compare_or_replace $1 $2 $3 || { + echo "copy file: $2 error" + exit 1 + } + } +} + +function install_file() { + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } + test -f $2 && { + cat $2 | sed -e 's;{install_path};'$INSTALL_PATH';;' >$tempdir/junk2 || { + echo "can't create file: $tempdir/junk2" + exit 1 + } + compare_or_replace $1 $tempdir/junk2 $3 || { + echo "can't move to file: $3" + exit 1 + } + } + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } +} + +############################################################################### +INSTALL_PATH= + +if [ $# -lt 1 ] +then +# echo "parameter not enougth($#)" + echo "usage:$0 install_path" + exit 1 +fi + +if [ $# -eq 2 ] +then + PREFIX_PATH=$1 + INSTALL_PATH=$2 +else + INSTALL_PATH=$1 + PREFIX_PATH= +fi + +case $INSTALL_PATH in +/*) ;; +no) ;; +*) echo Error: $INSTALL_PATH should be an absolute path name. 1>&2; exit 1;; +esac + +echo Installing to $INSTALL_PATH... + +BIN_PATH=$PREFIX_PATH$INSTALL_PATH/bin +SBIN_PATH=$PREFIX_PATH$INSTALL_PATH/sbin +CONF_PATH=$PREFIX_PATH$INSTALL_PATH/conf +SH_PATH=$PREFIX_PATH$INSTALL_PATH/sh +VAR_PATH=$PREFIX_PATH$INSTALL_PATH/var + +SERVICE_NAME=pkv +SERVICE_BIN=$SBIN_PATH/$SERVICE_NAME +SERVICE_CONF=$CONF_PATH/$SERVICE_NAME.cf +############################################################################### + +function create_all_path() { + create_path $INSTALL_PATH + create_path $BIN_PATH + create_path $SBIN_PATH + create_path $SH_PATH + create_path $CONF_PATH + create_path $VAR_PATH + create_path $VAR_PATH/log + create_path $VAR_PATH/pid + chmod 1777 $VAR_PATH/log +} + +function copy_all_file() { + copy_file a+x,go+rx $SERVICE_NAME $SERVICE_BIN + install_file a+x,go-wrx $SERVICE_NAME.cf $SERVICE_CONF +} + +MASTER_PATH=/opt/soft/acl-master +MASTER_CONF=$MASTER_PATH/conf +MASTER_SERVICES=$MASTER_CONF/services.cf +MASTER_CTL=$MASTER_PATH/bin/master_ctl + +function add_master_service() { + echo "" + + if [ ! -d $MASTER_CONF ]; then + echo "$MASTER_CONF not exist!" + return + fi + + if [ -f $MASTER_SERVICES ]; then + has=`cat $MASTER_SERVICES | grep $SERVICE_CONF | wc -l` + if [ $has != 0 ]; then + echo "Service for $SERVICE_CONF already in $MASTER_SERVICES!" + return + fi + fi + + echo "$SERVICE_CONF" >> $MASTER_SERVICES + echo "Service added for $SERVICE_CONF" + + if [ -f $MASTER_CTL ]; then + echo "Start your service by running:" + echo "$MASTER_CTL -f $SERVICE_CONF -a start" + fi +} + +guess_os +create_all_path +copy_all_file +add_master_service + +############################################################################### diff --git a/app/wizard_demo/pkv/stdafx.cpp b/app/wizard_demo/pkv/stdafx.cpp new file mode 100644 index 000000000..f01a2ff42 --- /dev/null +++ b/app/wizard_demo/pkv/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : ֻ׼ļԴļ +// master_threads.pch ΪԤͷ +// stdafx.obj ԤϢ + +#include "stdafx.h" + +// TODO: STDAFX.H +//κĸͷļڴļ diff --git a/app/wizard_demo/pkv/stdafx.h b/app/wizard_demo/pkv/stdafx.h new file mode 100644 index 000000000..fc909499c --- /dev/null +++ b/app/wizard_demo/pkv/stdafx.h @@ -0,0 +1,65 @@ +// stdafx.h : ׼ϵͳļİļ +// dzõĵĿضİļ +// + +#pragma once + + +//#include +//#include +#include + +// TODO: ڴ˴óҪĸͷļ + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" +#include "fiber/lib_fiber.h" +#include "fiber/lib_fiber.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#undef logger +#undef logger_warn +#undef logger_error +#undef logger_fatal +#undef logger_debug + +#if defined(_WIN32) || defined(_WIN64) + +# if _MSC_VER >= 1500 +# define logger(fmt, ...) \ + acl::log::msg4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +# define logger_warn(fmt, ...) \ + acl::log::warn4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +# define logger_error(fmt, ...) \ + acl::log::error4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +# define logger_fatal(fmt, ...) \ + acl::log::fatal4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +# define logger_debug(section, level, fmt, ...) \ + acl::log::msg6(section, level, __FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +# else +# define logger acl::log::msg1 +# define logger_warn acl::log::warn1 +# define logger_error acl::log::error1 +# define logger_fatal acl::log::fatal1 +# define logger_debug acl::log::msg3 +# endif +#else +# define logger(fmt, args...) \ + acl::log::msg4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +# define logger_warn(fmt, args...) \ + acl::log::warn4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +# define logger_error(fmt, args...) \ + acl::log::error4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +# define logger_fatal(fmt, args...) \ + acl::log::fatal4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +# define logger_debug(section, level, fmt, args...) \ + acl::log::msg6(section, level, __FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#endif // !_WIN32 && !_WIN64 + +extern acl::master_str_tbl var_conf_str_tab[]; +extern acl::master_bool_tbl var_conf_bool_tab[]; +extern acl::master_int_tbl var_conf_int_tab[]; +extern acl::master_int64_tbl var_conf_int64_tab[]; diff --git a/app/wizard_demo/pkv/valgrind.sh b/app/wizard_demo/pkv/valgrind.sh new file mode 100755 index 000000000..ee06dc658 --- /dev/null +++ b/app/wizard_demo/pkv/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./pkv alone pkv.cf diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp index 6156b5e01..2b1198610 100644 --- a/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp @@ -204,6 +204,7 @@ private: friend class redis_client; void clear(void); +public: redis_result& set_type(redis_result_t type); redis_result& set_size(size_t size); redis_result& put(const char* buf, size_t len); diff --git a/lib_acl_cpp/samples/Makefile.in b/lib_acl_cpp/samples/Makefile.in index d0b082e50..fe3aa2275 100644 --- a/lib_acl_cpp/samples/Makefile.in +++ b/lib_acl_cpp/samples/Makefile.in @@ -58,7 +58,8 @@ endif ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) # CC += -arch x86_64 -arch arm64 CFLAGS += -DMACOSX -Wno-invalid-source-encoding \ - -Wno-invalid-offsetof + -Wno-invalid-offsetof \ + -Wno-deprecated-declarations SYSLIB += -liconv -rdynamic UNIXTYPE = MACOSX RPATH = macos diff --git a/lib_acl_cpp/samples/benchmark/rosksdb/Makefile.in b/lib_acl_cpp/samples/benchmark/rosksdb/Makefile.in index 05bc5c0f9..0141961be 100644 --- a/lib_acl_cpp/samples/benchmark/rosksdb/Makefile.in +++ b/lib_acl_cpp/samples/benchmark/rosksdb/Makefile.in @@ -3,7 +3,7 @@ CC = g++ CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ -Wno-long-long \ -Wpointer-arith -Werror -Wshadow -O3 \ --D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO -std=c++11 +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO -std=c++17 #-Waggregate-return ########################################################### @@ -65,10 +65,11 @@ endif CFLAGS += -I. -I../.. -I../../../include -I../../../../lib_acl/include -I../../../../lib_protocol/include EXTLIBS = -CFLAGS += -I/home/zsx/download/db/rocksdb/include +#CFLAGS += -I/home/zsx/download/db/rocksdb/include #EXTLIBS = -L/home/zsx/download/db/rocksdb/build -lrocksdb -Wl,-rpath=/home/zsx/download/db/rocksdb/build \ # -L/home/zsx/download/snappy/build -lsnappy -EXTLIBS = /home/zsx/download/db/rocksdb/build/librocksdb.a +#EXTLIBS = /home/zsx/download/db/rocksdb/build/librocksdb.a +EXTLIBS = -lrocksdb -Wl,-rpath,/usr/local/lib LDFLAGS = -L../../../lib -l_acl_cpp -L../../../../lib_protocol/lib -l_protocol -L../../../../lib_acl/lib -l_acl \ $(EXTLIBS) $(SYSLIB) diff --git a/lib_acl_cpp/samples/redis/redis_hash/redis_hash.cpp b/lib_acl_cpp/samples/redis/redis_hash/redis_hash.cpp index a276dc99c..7a5912789 100644 --- a/lib_acl_cpp/samples/redis/redis_hash/redis_hash.cpp +++ b/lib_acl_cpp/samples/redis/redis_hash/redis_hash.cpp @@ -391,6 +391,7 @@ static void usage(const char* procname) { printf("usage: %s -h[help]\r\n" "-s redis_addr[127.0.0.1:6379]\r\n" + "-p passwd\r\n" "-n count\r\n" "-C connect_timeout[default: 10]\r\n" "-I rw_timeout[default: 10]\r\n" @@ -403,10 +404,10 @@ static void usage(const char* procname) int main(int argc, char* argv[]) { int ch, n = 1, conn_timeout = 10, rw_timeout = 10; - acl::string addr("127.0.0.1:6379"), cmd; + acl::string addr("127.0.0.1:6379"), cmd, passwd; bool slice_req = false, cluster_mode = false; - while ((ch = getopt(argc, argv, "hs:n:C:I:a:Sc")) > 0) + while ((ch = getopt(argc, argv, "hs:p:n:C:I:a:Sc")) > 0) { switch (ch) { @@ -416,6 +417,9 @@ int main(int argc, char* argv[]) case 's': addr = optarg; break; + case 'p': + passwd = optarg; + break; case 'n': n = atoi(optarg); break; @@ -450,9 +454,16 @@ int main(int argc, char* argv[]) acl::redis_hash redis; if (cluster_mode) + { + if (!passwd.empty()) + cluster.set_password("default", passwd); redis.set_cluster(&cluster); - else + } else + { + if (!passwd.empty()) + client.set_password(passwd); redis.set_client(&client); + } bool ret; diff --git a/lib_acl_cpp/src/redis/redis_client.cpp b/lib_acl_cpp/src/redis/redis_client.cpp index 1a6f7339c..78b9a2efc 100644 --- a/lib_acl_cpp/src/redis/redis_client.cpp +++ b/lib_acl_cpp/src/redis/redis_client.cpp @@ -246,8 +246,9 @@ redis_result* redis_client::get_string(socket_stream& conn, dbuf_pool* dbuf) redis_result* rr = new(dbuf) redis_result(dbuf); rr->set_type(REDIS_RESULT_STRING); int len = atoi(sbuf.c_str()); - if (len < 0) + if (len <= 0) { return rr; + } char* buf; @@ -315,8 +316,9 @@ redis_result* redis_client::get_array(socket_stream& conn, dbuf_pool* dbuf) redis_result* rr = new(dbuf) redis_result(dbuf); rr->set_type(REDIS_RESULT_ARRAY); int count = atoi(buf.c_str()); - if (count <= 0) + if (count <= 0) { return rr; + } rr->set_size((size_t) count); diff --git a/lib_fiber/c/src/hook/fcntl.c b/lib_fiber/c/src/hook/fcntl.c index c73a34ee5..b7568b005 100644 --- a/lib_fiber/c/src/hook/fcntl.c +++ b/lib_fiber/c/src/hook/fcntl.c @@ -54,6 +54,12 @@ int fcntl(int fd, int cmd, ...) case F_SETSIG: case F_SETLEASE: case F_NOTIFY: +#ifdef F_GET_RW_HINT + case F_GET_RW_HINT: +#endif +#ifdef F_SET_RW_HINT + case F_SET_RW_HINT: +#endif #ifdef F_SETPIPE_SZ case F_SETPIPE_SZ: #endif diff --git a/lib_fiber/samples/Makefile.in b/lib_fiber/samples/Makefile.in index 5a2c68a52..a677ce337 100644 --- a/lib_fiber/samples/Makefile.in +++ b/lib_fiber/samples/Makefile.in @@ -81,6 +81,12 @@ ifeq ($(findstring Linux, $(UNIXNAME)), Linux) ifeq ($(has_io_uring), yes) SYSLIB += -luring-ffi endif + ifeq ($(DEBUG_STACK), yes) + SYSLIB += -lunwind -lunwind-generic + endif + ifeq ($(debug_stack), yes) + SYSLIB += -lunwind -lunwind-generic + endif endif # For CYGWIN diff --git a/lib_fiber/samples/dead_lock/Makefile b/lib_fiber/samples/dead_lock/Makefile index c3f7932a3..25f1bbce0 100644 --- a/lib_fiber/samples/dead_lock/Makefile +++ b/lib_fiber/samples/dead_lock/Makefile @@ -1,6 +1,3 @@ # Don't build the sample on MacOS because libunwind don't support it. include ../Makefile.in -ifeq ($(findstring Linux, $(UNIXNAME)), Linux) - SYSLIB += -lunwind -lunwind-x86_64 -endif PROG = dead_lock diff --git a/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp b/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp index 097d30a10..568a9b482 100644 --- a/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp +++ b/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp @@ -2,11 +2,11 @@ static acl::string __keypre("test_key_cluster"); -static bool test_del(acl::redis_key& cmd, int i) +static bool test_del(acl::redis_key& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); int ret = cmd.del(key.c_str()); if (ret < 0) { printf("del key: %s error: %s\r\n", @@ -18,11 +18,11 @@ static bool test_del(acl::redis_key& cmd, int i) return true; } -static bool test_expire(acl::redis_key& cmd, int i) +static bool test_expire(acl::redis_key& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); if (cmd.expire(key.c_str(), 100) < 0) { printf("expire key: %s error: %s\r\n", key.c_str(), cmd.result_error()); @@ -34,12 +34,12 @@ static bool test_expire(acl::redis_key& cmd, int i) return true; } -static bool test_ttl(acl::redis_key& cmd, int i) +static bool test_ttl(acl::redis_key& cmd, size_t tid, size_t fid, int i) { acl::string key; int ttl; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); if ((ttl = cmd.ttl(key.c_str())) < 0) { printf("get ttl key: %s error: %s\r\n", key.c_str(), cmd.result_error()); @@ -50,11 +50,11 @@ static bool test_ttl(acl::redis_key& cmd, int i) return true; } -static bool test_exists(acl::redis_key& cmd, int i) +static bool test_exists(acl::redis_key& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); if (!cmd.exists(key.c_str())) { if (i < 10) { printf("no exists key: %s\r\n", key.c_str()); @@ -67,11 +67,11 @@ static bool test_exists(acl::redis_key& cmd, int i) return true; } -static bool test_type(acl::redis_key& cmd, int i) +static bool test_type(acl::redis_key& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); acl::redis_key_t ret = cmd.type(key.c_str()); if (ret == acl::REDIS_KEY_NONE) { printf("unknown type key: %s\r\n", key.c_str()); @@ -82,10 +82,10 @@ static bool test_type(acl::redis_key& cmd, int i) return true; } -static bool test_set(acl::redis_string& cmd, int i) +static bool test_set(acl::redis_string& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); acl::string value; value.format("value_%s", key.c_str()); @@ -99,10 +99,10 @@ static bool test_set(acl::redis_string& cmd, int i) return ret; } -static bool test_get(acl::redis_string& cmd, int i) +static bool test_get(acl::redis_string& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("%s_%d", __keypre.c_str(), i); + key.format("%s_%zd_%zd_%d", __keypre.c_str(), tid, fid, i); acl::string value; @@ -115,10 +115,10 @@ static bool test_get(acl::redis_string& cmd, int i) return ret; } -static bool test_hmset(acl::redis_hash& cmd, int i) +static bool test_hmset(acl::redis_hash& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("hash-%s-%d", __keypre.c_str(), i); + key.format("hash-%s-%zd-%zd-%d", __keypre.c_str(), tid, fid, i); std::map attrs; attrs["name1"] = "value1"; @@ -135,10 +135,10 @@ static bool test_hmset(acl::redis_hash& cmd, int i) return true; } -static bool test_hmget(acl::redis_hash& cmd, int i) +static bool test_hmget(acl::redis_hash& cmd, size_t tid, size_t fid, int i) { acl::string key; - key.format("hash-%s-%d", __keypre.c_str(), i); + key.format("hash-%s-%zd-%zd-%d", __keypre.c_str(), tid, fid, i); std::vector names; names.push_back("name1"); @@ -170,8 +170,11 @@ static int __threads_exit = 0; class test_fiber : public acl::fiber { public: - test_fiber(acl::redis_client_pipeline& conns, const char* cmd, int n) - : conns_(conns) + test_fiber(size_t tid, size_t fid, acl::redis_client_pipeline& conns, + const char* cmd, int n) + : tid_(tid) + , fid_(fid) + , conns_(conns) , cmd_(cmd) , n_(n) {} @@ -188,35 +191,35 @@ protected: for (int i = 0; i < n_; i++) { if (cmd_ == "set") { - ret = test_set(redis, i); + ret = test_set(redis, tid_, fid_, i); } else if (cmd_ == "get") { - ret = test_get(redis, i); + ret = test_get(redis, tid_, fid_, i); } else if (cmd_ == "del") { - ret = test_del(redis, i); + ret = test_del(redis, tid_, fid_, i); } else if (cmd_ == "expire") { - ret = test_expire(redis, i); + ret = test_expire(redis, tid_, fid_, i); } else if (cmd_ == "ttl") { - ret = test_ttl(redis, i); + ret = test_ttl(redis, tid_, fid_, i); } else if (cmd_ == "exists") { - ret = test_exists(redis, i); + ret = test_exists(redis, tid_, fid_, i); } else if (cmd_ == "type") { - ret = test_type(redis, i); + ret = test_type(redis, tid_, fid_, i); } else if (cmd_ == "all") { - if (!test_set(redis, i) - || !test_get(redis, i) - || !test_exists(redis, i) - || !test_type(redis, i) - || !test_expire(redis, i) - || !test_ttl(redis, i) - || !test_del(redis, i)) { + if (!test_set(redis, tid_, fid_, i) + || !test_get(redis, tid_, fid_, i) + || !test_exists(redis, tid_, fid_, i) + || !test_type(redis, tid_, fid_, i) + || !test_expire(redis, tid_, fid_, i) + || !test_ttl(redis, tid_, fid_, i) + || !test_del(redis, tid_, fid_, i)) { ret = false; } else { ret = true; } } else if (cmd_ == "hmset") { - ret = test_hmset(redis, i); + ret = test_hmset(redis, tid_, fid_, i); } else if (cmd_ == "hmget") { - ret = test_hmget(redis, i); + ret = test_hmget(redis, tid_, fid_, i); } else { printf("unknown cmd: %s\r\n", cmd_.c_str()); break; @@ -241,6 +244,8 @@ protected: } private: + size_t tid_; + size_t fid_; acl::redis_client_pipeline& conns_; acl::string cmd_; //acl::redis redis; @@ -250,10 +255,12 @@ private: class test_thread : public acl::thread { public: - test_thread(acl::locker& locker, acl::redis_client_pipeline& conns, - const char* cmd, int n, size_t nfibers, size_t stack_size, - bool share_stack) - : locker_(locker) + test_thread(size_t tid, acl::locker& locker, + acl::redis_client_pipeline& conns, + const char* cmd, int n, size_t nfibers, + size_t stack_size, bool share_stack) + : tid_(tid) + , locker_(locker) , conns_(conns) , cmd_(cmd) , n_(n) @@ -269,7 +276,7 @@ protected: { std::vector fibers; for (size_t i = 0; i < nfibers_; i++) { - test_fiber* fb = new test_fiber(conns_, cmd_, n_); + test_fiber* fb = new test_fiber(tid_, i, conns_, cmd_, n_); fibers.push_back(fb); fb->start(stack_size_, share_stack_); } @@ -288,6 +295,7 @@ protected: } private: + size_t tid_; acl::locker& locker_; acl::redis_client_pipeline& conns_; acl::string cmd_; @@ -393,8 +401,9 @@ int main(int argc, char* argv[]) std::vector threads; for (int i = 0; i < max_threads; i++) { - test_thread* thread = new test_thread(locker, *pipeline, - cmd.c_str(), n, nfibers, stack_size, share_stack); + test_thread* thread = new test_thread((size_t) i, locker, + *pipeline, cmd.c_str(), n, nfibers, + stack_size, share_stack); threads.push_back(thread); thread->set_detachable(true); thread->start(); diff --git a/lib_fiber/samples/redis_threads/main.cpp b/lib_fiber/samples/redis_threads/main.cpp index 6588d4f7b..19ce4d253 100644 --- a/lib_fiber/samples/redis_threads/main.cpp +++ b/lib_fiber/samples/redis_threads/main.cpp @@ -78,12 +78,12 @@ int main(int argc, char *argv[]) for (int i = 0; i < nthreads; i++) { redis_thread* thread; if (use_global_cluster) { - thread = new redis_thread(cluster, fibers_max, + thread = new redis_thread(i, cluster, fibers_max, stack_size, oper_count, cmd); } else { - thread = new redis_thread(addr, passwd, conn_timeout, - rw_timeout, fibers_max, stack_size, - oper_count, cmd); + thread = new redis_thread(i, addr, passwd, + conn_timeout, rw_timeout, fibers_max, + stack_size, oper_count, cmd); } thread->set_detachable(false); thread->set_stacksize(stack_size * (fibers_max + 6400)); diff --git a/lib_fiber/samples/redis_threads/redis_thread.cpp b/lib_fiber/samples/redis_threads/redis_thread.cpp index 05f5918e3..230e22060 100644 --- a/lib_fiber/samples/redis_threads/redis_thread.cpp +++ b/lib_fiber/samples/redis_threads/redis_thread.cpp @@ -18,25 +18,24 @@ static double stamp_sub(const struct timeval *from, return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); } -static int redis_set(acl::redis& cmd, const struct timeval& begin, int count) +static int redis_set(int tid, int fid, acl::redis& cmd, + const struct timeval& begin, int count) { acl::string key, val; int i = 0; for (; i < count; i++) { - key.format("key-%lu-%d-%d", acl::thread::self(), - acl_fiber_self(), i); - val.format("val-%lu-%d-%d", acl::thread::self(), - acl_fiber_self(), i); + key.format("key-%d-%d-%d", tid, fid, i); + val.format("val-%d-%d-%d", tid, fid, i); if (cmd.set(key, val) == false) { printf("fiber-%d: set error: %s, key: %s\r\n", - acl_fiber_self(), cmd.result_error(), + acl::fiber::self(), cmd.result_error(), key.c_str()); break; } else if (i < 5) { printf("fiber-%d: set ok, key: %s\r\n", - acl_fiber_self(), key.c_str()); + acl::fiber::self(), key.c_str()); } cmd.clear(); @@ -50,20 +49,24 @@ static int redis_set(acl::redis& cmd, const struct timeval& begin, int count) return i; } -static int redis_get(acl::redis& cmd, const struct timeval& begin, int count) +static int redis_get(int tid, int fid, acl::redis& cmd, + const struct timeval& begin, int count) { acl::string key, val; int i = 0; for (; i < count; i++) { - key.format("key-%lu-%d-%d", acl::thread::self(), - acl_fiber_self(), i); + key.format("key-%d-%d-%d", tid, fid, i); if (cmd.get(key, val) == false) { printf("fiber-%d: get error: %s, key: %s\r\n", - acl_fiber_self(), cmd.result_error(), + acl::fiber::self(), cmd.result_error(), key.c_str()); break; + } else if (i < 5) { + printf("fiber-%d: get ok, key: %s, val: %s\r\n", + acl::fiber::self(), key.c_str(), val.c_str()); } + val.clear(); cmd.clear(); } @@ -76,17 +79,17 @@ static int redis_get(acl::redis& cmd, const struct timeval& begin, int count) return i; } -static int redis_del(acl::redis& cmd, const struct timeval& begin, int count) +static int redis_del(int tid, int fid, acl::redis& cmd, + const struct timeval& begin, int count) { acl::string key; int i = 0; for (; i < count; i++) { - key.format("key-%lu-%d-%d", acl::thread::self(), - acl_fiber_self(), i); + key.format("key-%d-%d-%d", tid, fid, i); if (cmd.del_one(key) < 0) { printf("fiber-%d: del error: %s, key: %s\r\n", - acl_fiber_self(), cmd.result_error(), + acl::fiber::self(), cmd.result_error(), key.c_str()); break; } @@ -102,39 +105,64 @@ static int redis_del(acl::redis& cmd, const struct timeval& begin, int count) return i; } -void redis_thread::fiber_redis(ACL_FIBER *, void *ctx) -{ - redis_thread* thread = (redis_thread*) ctx; - acl::redis_client_cluster *cluster = &thread->get_cluster(); - acl::redis redis(cluster); - int oper_count = thread->get_oper_count(); - const acl::string& cmd = thread->get_cmd(); +/////////////////////////////////////////////////////////////////////////////// - int n = 0; - struct timeval begin; - - gettimeofday(&begin, NULL); - if (cmd == "set" || cmd == "all") { - n += ::redis_set(redis, begin, oper_count); +class fiber_redis : public acl::fiber { +public: + fiber_redis(int fid, redis_thread& thread) + : fid_(fid), thread_(thread) + { } - if (cmd == "get" || cmd == "all") { - gettimeofday(&begin, NULL); - n += redis_get(redis, begin, oper_count); +private: + ~fiber_redis() {} + +protected: + // @override + void run() { + acl::redis_client_cluster *cluster = &thread_.get_cluster(); + acl::redis redis(cluster); + int oper_count = thread_.get_oper_count(); + const acl::string& cmd = thread_.get_cmd(); + + int n = 0; + struct timeval begin; + + if (cmd == "set" || cmd == "all") { + gettimeofday(&begin, NULL); + n += redis_set(thread_.get_tid(), fid_, redis, + begin, oper_count); + } + + if (cmd == "get" || cmd == "all") { + gettimeofday(&begin, NULL); + n += redis_get(thread_.get_tid(), fid_, redis, + begin, oper_count); + } + + if (cmd == "del" || cmd == "all") { + gettimeofday(&begin, NULL); + n += redis_del(thread_.get_tid(), fid_, redis, + begin, oper_count); + } + + thread_.fiber_dec(n); + + delete this; } - if (cmd == "del" || cmd == "all") { - gettimeofday(&begin, NULL); - n += redis_del(redis, begin, oper_count); - } +private: + int fid_; + redis_thread& thread_; +}; - thread->fiber_dec(n); -} +/////////////////////////////////////////////////////////////////////////////// -redis_thread::redis_thread(const char* addr, const char* passwd, +redis_thread::redis_thread(int tid, const char* addr, const char* passwd, int conn_timeout, int rw_timeout, int fibers_max, int stack_size, int oper_count, const char* cmd) -: addr_(addr) +: tid_(tid) +, addr_(addr) , passwd_(passwd) , conn_timeout_(conn_timeout) , rw_timeout_(rw_timeout) @@ -152,9 +180,10 @@ redis_thread::redis_thread(const char* addr, const char* passwd, cluster_->set_password("default", passwd_); } -redis_thread::redis_thread(acl::redis_client_cluster& cluster, int fibers_max, - int stack_size, int oper_count, const char* cmd) -: fibers_max_(fibers_max) +redis_thread::redis_thread(int tid, acl::redis_client_cluster& cluster, + int fibers_max, int stack_size, int oper_count, const char* cmd) +: tid_(tid) +, fibers_max_(fibers_max) , fibers_cnt_(fibers_max) , stack_size_(stack_size) , oper_count_(oper_count) @@ -174,10 +203,11 @@ void* redis_thread::run(void) gettimeofday(&begin_, NULL); for (int i = 0; i < fibers_max_; i++) { - acl_fiber_create(fiber_redis, this, stack_size_); + acl::fiber* fb = new fiber_redis(i, *this); + fb->start(); } - acl_fiber_schedule(); + acl::fiber::schedule(); return NULL; } diff --git a/lib_fiber/samples/redis_threads/redis_thread.h b/lib_fiber/samples/redis_threads/redis_thread.h index 873e39c15..5244dafd4 100644 --- a/lib_fiber/samples/redis_threads/redis_thread.h +++ b/lib_fiber/samples/redis_threads/redis_thread.h @@ -3,15 +3,18 @@ class redis_thread : public acl::thread { public: - redis_thread(const char* addr, const char* passwd, int conn_timeout, - int rw_timeout, int fibers_max, int stack_size, - int oper_count, const char* cmd); - redis_thread(acl::redis_client_cluster& cluster, int fibers_max, + redis_thread(int tid, const char* addr, const char* passwd, + int conn_timeout, int rw_timeout, int fibers_max, + int stack_size, int oper_count, const char* cmd); + redis_thread(int tid, acl::redis_client_cluster& cluster, int fibers_max, int stack_size, int oper_count, const char* cmd); ~redis_thread(void); -private: + int get_tid(void) const { + return tid_; + } + acl::redis_client_cluster& get_cluster(void) { return *cluster_; @@ -42,6 +45,7 @@ protected: void *run(void); private: + int tid_; acl::string addr_; acl::string passwd_; int conn_timeout_; @@ -55,6 +59,4 @@ private: struct timeval begin_; acl::redis_client_cluster* cluster_; acl::redis_client_cluster* cluster_internal_; - - static void fiber_redis(ACL_FIBER *fiber, void *ctx); }; diff --git a/lib_fiber/samples/redis_threads/stdafx.h b/lib_fiber/samples/redis_threads/stdafx.h index f3746ace7..194e37030 100644 --- a/lib_fiber/samples/redis_threads/stdafx.h +++ b/lib_fiber/samples/redis_threads/stdafx.h @@ -11,7 +11,7 @@ // TODO: ڴ˴óҪĸͷļ #include "lib_acl.h" -#include "fiber/libfiber.h" +#include "fiber/libfiber.hpp" #include "acl_cpp/lib_acl.hpp" #ifdef WIN32