/************************************************************************ * * Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved * $Id: cli_sdk.cc,v 1.0 08/06/2016 04:53:21 PM hangfeng.fj(hangfeng.fj@alibaba-inc.com) $ * ************************************************************************/ /** * @file cli_sdk.cc * @author hangfeng.fj(hangfeng.fj@alibaba-inc.com) * @date 08/25/2016 04:53:21 PM * @version 1.0 * @brief * **/ #include "cli_sdk.h" #include #include #include #include #include DECLARE_string(server_members); namespace alisql { static memcached_return_t stat_printer(const memcached_instance_st * instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) { static const memcached_instance_st * last= NULL; bool *isLeader = (bool*)context; printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value); if (strcmp(key, "role") == 0 && strcmp(value, "LEADER") == 0 && isLeader != NULL) { *isLeader= true; } return MEMCACHED_SUCCESS; } int CliSDK::parseArgs(int argc, char* argv[], std::vector &members) { google::ParseCommandLineFlags(&argc, &argv, true); boost::split(members, FLAGS_server_members, boost::is_any_of(","), boost::token_compress_on); if (members.size() == 0) { LOG_INFO("server members is empty , please check your configuration\n"); return -1; } return 0; } CliSDK::CliSDK(const std::vector &members) : stop_(false), memc_(NULL), casUnique_(0), rc_(MEMCACHED_SUCCESS) { init(members); } CliSDK::~CliSDK() { if (memc_ != NULL) { memcached_free(memc_); memc_= NULL; } } void CliSDK::init(const std::vector &members) { std::copy(members.begin(), members.end(), std::back_inserter(members_)); } void CliSDK::sortMemberList(std::vector& memberList) { if (!leaderId_.empty()) { memberList.push_back(leaderId_); } std::copy(members_.begin(), members_.end(), std::back_inserter(memberList)); } int CliSDK::memConnect(const char *hostname, int port) { if (memc_ != NULL) { //LOG_INFO("memc_ is not NULL\n"); return -1; } memcached_return rc; memcached_server_st *server; memc_= memcached_create(NULL); server= memcached_server_list_append(NULL, hostname, port, &rc); if (rc != MEMCACHED_SUCCESS) { //LOG_INFO("memcached_server_list_append fail\n"); return -1; } rc= memcached_server_push(memc_, server); if (rc != MEMCACHED_SUCCESS) { //LOG_INFO("memcached_server_push fail\n"); return -1; } memcached_server_list_free(server); } int CliSDK::processInternal(SDKOpr opr, const std::string &key, std::string &value) { std::string oprStr; if (opr == Put) { rc_= memcached_set(memc_, key.c_str(), key.length(), value.c_str(), value.length(), 0, 0); } else if (opr == Del) { rc_= memcached_delete(memc_, key.c_str(), key.length(), 0); } else if (opr == Get) { uint32_t flags; size_t value_length= 0; memcached_behavior_set(memc_, MEMCACHED_BEHAVIOR_SUPPORT_CAS, false); char* result= memcached_get(memc_, key.c_str(), key.length(), &value_length, &flags, &rc_); if (result != NULL) { value= result; } } else if (opr == Gets) { size_t keyLength= key.length(); const char *p= reinterpret_cast(&key[0]); memcached_behavior_set(memc_, MEMCACHED_BEHAVIOR_SUPPORT_CAS, true); rc_= memcached_mget(memc_, &p, &keyLength, 1); memcached_result_st results_obj; memcached_result_st *results= memcached_result_create(memc_, &results_obj); if (results == NULL) { //LOG_INFO("Fail to create result\n"); return -1; } results= memcached_fetch_result(memc_, &results_obj, &rc_); if (results == NULL || rc_ != MEMCACHED_SUCCESS) { //LOG_INFO("Fail to get result\n"); return -1; } value= memcached_result_value(results); casUnique_= memcached_result_cas(results); memcached_result_free(&results_obj); } else if (opr == Cas) { rc_= memcached_cas(memc_, key.c_str(), key.length(), value.c_str(), value.length(), 0, 0, casUnique_); } if (memcached_success(rc_)) { return 0; } // Route the request to another server if this member is not leader now // or it is offline else { return -1; } } int CliSDK::put(const std::string &key, std::string &value) { return process(Put, key, value); } int CliSDK::get(const std::string &key, std::string &value) { return process(Get, key, value); } int CliSDK::del(const std::string &key) { std::string value; return process(Del, key, value); } int CliSDK::gets(const std::string &key, std::string &value) { return process(Gets, key, value); } int CliSDK::cas(const std::string &key, std::string &value) { return process(Cas, key, value); } int CliSDK::showStats() { for (int i= 0; i < members_.size(); i++) { std::string memberId= members_[i]; memcached_server_st* servers= memcached_servers_parse(memberId.c_str()); if (servers == NULL || memcached_server_list_count(servers) == 0) { LOG_INFO("Invalid server provided: %s \n", memberId.c_str()); return -1; } memcached_st *memc= memcached_create(NULL); memcached_return_t rc= memcached_server_push(memc, servers); memcached_server_list_free(servers); if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) { return -1; } printf("-----------------------------------------\n"); printf("Server: %s\n", memberId.c_str()); printf("Local stats info:\n"); bool isLeader= false; rc= memcached_stat_execute(memc, "local", stat_printer, &isLeader); if (memcached_fatal(rc)) { printf("\t is offline \n"); } if (isLeader) { printf("Cluster stats info:\n"); rc= memcached_stat_execute(memc, "cluster", stat_printer, NULL); } memcached_free(memc); } return 0; } int CliSDK::parseIpPort(std::string &ipPortStr, std::string *ip, int *port) { try { std::vector ipPort; boost::split(ipPort, ipPortStr, boost::is_any_of(":"), boost::token_compress_on); if (ipPort.size() < 2) { LOG_INFO("Member address %s format error, please check your configuration!\n", ipPortStr.c_str()); return -1; } *ip= ipPort[0]; std::string portStr= ipPort[1]; *port= boost::lexical_cast(portStr); } catch(std::exception& e) { printf("Parse address failed \n"); return -1; } return 0; } int CliSDK::process(SDKOpr opr, const std::string &key, std::string &value) { int ret= 0; if (!leaderId_.empty() && memc_ != NULL) { ret= processInternal(opr, key, value); if (ret == 0) { return 0; } if (opr == Cas && rc_ == MEMCACHED_DATA_EXISTS) { return -1; } } for (int i= 0; i < members_.size(); i++) { std::string memberId= members_[i]; std::string ip; int port; ret= parseIpPort(memberId, &ip, &port); if (ret != 0) { LOG_INFO("Invalid address format for %s!\n", memberId.c_str()); continue; } if (memc_ != NULL) { memcached_free(memc_); memc_= NULL; } ret= memConnect(ip.c_str(), port); if (memc_ == NULL) { continue; } ret= processInternal(opr, key, value); if (ret == 0) { leaderId_= memberId; return ret; } if (opr == Cas && rc_ == MEMCACHED_DATA_EXISTS) { return -1; } } return ret; } } //namespace alisql