diff options
Diffstat (limited to '')
22 files changed, 2723 insertions, 0 deletions
diff --git a/storage/spider/hs_client/allocator.hpp b/storage/spider/hs_client/allocator.hpp new file mode 100644 index 00000000..c302e078 --- /dev/null +++ b/storage/spider/hs_client/allocator.hpp @@ -0,0 +1,43 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_ALLOCATOR_HPP +#define DENA_ALLOCATOR_HPP + +#if 0 +extern "C" { +#include <tlsf.h> +}; +#define DENA_MALLOC(x) tlsf_malloc(x) +#define DENA_REALLOC(x, y) tlsf_realloc(x, y) +#define DENA_FREE(x) tlsf_free(x) +#define DENA_NEWCHAR(x) static_cast<char *>(tlsf_malloc(x)) +#define DENA_DELETE(x) tlsf_free(x) +#endif + +#if 1 +#define DENA_MALLOC(x) malloc(x) +#define DENA_REALLOC(x, y) realloc(x, y) +#define DENA_FREE(x) free(x) +#define DENA_NEWCHAR(x) (new char[x]) +#define DENA_DELETE(x) (delete [] x) +#endif + +#if 1 +#define DENA_ALLOCA_ALLOCATE(typ, len) \ + (typ *) (alloca((len) * sizeof(typ))) +#define DENA_ALLOCA_FREE(x) +#else +#define DENA_ALLOCA_ALLOCATE(typ, len) \ + (typ *) (malloc((len) * sizeof(typ))) +#define DENA_ALLOCA_FREE(x) free(x) +#endif + +#endif + diff --git a/storage/spider/hs_client/auto_addrinfo.hpp b/storage/spider/hs_client/auto_addrinfo.hpp new file mode 100644 index 00000000..5262ad11 --- /dev/null +++ b/storage/spider/hs_client/auto_addrinfo.hpp @@ -0,0 +1,49 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_AUTO_ADDRINFO_HPP +#define DENA_AUTO_ADDRINFO_HPP + +#ifndef __WIN__ +#include <netdb.h> +#endif + +#include "util.hpp" + +namespace dena { + +struct auto_addrinfo : private noncopyable { + auto_addrinfo() : addr(0) { } + ~auto_addrinfo() { + reset(); + } + void reset(addrinfo *a = 0) { + if (addr != 0) { + freeaddrinfo(addr); + } + addr = a; + } + const addrinfo *get() const { return addr; } + int resolve(const char *node, const char *service, int flags = 0, + int family = AF_UNSPEC, int socktype = SOCK_STREAM, int protocol = 0) { + reset(); + addrinfo hints; + hints.ai_flags = flags; + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; + return getaddrinfo(node, service, &hints, &addr); + } + private: + addrinfo *addr; +}; + +}; + +#endif + diff --git a/storage/spider/hs_client/auto_file.hpp b/storage/spider/hs_client/auto_file.hpp new file mode 100644 index 00000000..ddd1f8c9 --- /dev/null +++ b/storage/spider/hs_client/auto_file.hpp @@ -0,0 +1,67 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_AUTO_FILE_HPP +#define DENA_AUTO_FILE_HPP + +/* +#ifndef __WIN__ +#include <dirent.h> +#endif +*/ + +#include "util.hpp" + +namespace dena { + +struct auto_file : private noncopyable { + auto_file() : fd(-1) { } + ~auto_file() { + reset(); + } + int get() const { return fd; } + int close() { + if (fd < 0) { + return 0; + } + const int r = ::close(fd); + fd = -1; + return r; + } + void reset(int x = -1) { + if (fd >= 0) { + this->close(); + } + fd = x; + } + private: + int fd; +}; + +/* +struct auto_dir : private noncopyable { + auto_dir() : dp(0) { } + ~auto_dir() { + reset(); + } + DIR *get() const { return dp; } + void reset(DIR *d = 0) { + if (dp != 0) { + closedir(dp); + } + dp = d; + } + private: + DIR *dp; +}; +*/ + +}; + +#endif + diff --git a/storage/spider/hs_client/auto_ptrcontainer.hpp b/storage/spider/hs_client/auto_ptrcontainer.hpp new file mode 100644 index 00000000..3629f19c --- /dev/null +++ b/storage/spider/hs_client/auto_ptrcontainer.hpp @@ -0,0 +1,70 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_AUTO_PTRCONTAINER_HPP +#define DENA_AUTO_PTRCONTAINER_HPP + +namespace dena { + +/* +template <typename Tcnt> +struct auto_ptrcontainer { + typedef Tcnt container_type; + typedef typename container_type::value_type value_type; + typedef typename container_type::pointer pointer; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + typedef typename container_type::size_type size_type; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::reverse_iterator reverse_iterator; + typedef typename container_type::const_reverse_iterator + const_reverse_iterator; + iterator begin() { return cnt.begin(); } + const_iterator begin() const { return cnt.begin(); } + iterator end() { return cnt.end(); } + const_iterator end() const { return cnt.end(); } + reverse_iterator rbegin() { return cnt.rbegin(); } + reverse_iterator rend() { return cnt.rend(); } + const_reverse_iterator rbegin() const { return cnt.rbegin(); } + const_reverse_iterator rend() const { return cnt.rend(); } + size_type size() const { return cnt.size(); } + size_type max_size() const { return cnt.max_size(); } + bool empty() const { return cnt.empty(); } + reference front() { return cnt.front(); } + const_reference front() const { cnt.front(); } + reference back() { return cnt.back(); } + const_reference back() const { cnt.back(); } + void swap(auto_ptrcontainer& x) { cnt.swap(x.cnt); } + ~auto_ptrcontainer() { + for (iterator i = begin(); i != end(); ++i) { + delete *i; + } + } + template <typename Tap> void push_back_ptr(Tap& ap) { + cnt.push_back(ap.get()); + ap.release(); + } + void erase_ptr(iterator i) { + delete *i; + cnt.erase(i); + } + reference operator [](size_type n) { return cnt[n]; } + const_reference operator [](size_type n) const { return cnt[n]; } + void clear() { cnt.clear(); } + private: + Tcnt cnt; +}; +*/ + +}; + +#endif + diff --git a/storage/spider/hs_client/config.cpp b/storage/spider/hs_client/config.cpp new file mode 100644 index 00000000..0003c3fd --- /dev/null +++ b/storage/spider/hs_client/config.cpp @@ -0,0 +1,292 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "config.hpp" + +namespace dena { + +unsigned int verbose_level = 0; + +uchar * +conf_get_key( + conf_param *param, + size_t *length, + my_bool not_used __attribute__ ((unused)) +) { + *length = param->key.length(); + return (uchar*) param->key.ptr(); +} + +config::config() +{ + if (my_hash_init(PSI_INSTRUMENT_ME, &conf_hash, &my_charset_bin, 32, 0, 0, + (my_hash_get_key) conf_get_key, 0, 0)) + init = FALSE; + else + init = TRUE; + return; +} + +config::~config() +{ + if (init) + { + conf_param *param; + while ((param = (conf_param *) my_hash_element(&conf_hash, 0))) + { + my_hash_delete(&conf_hash, (uchar*) param); + delete param; + } + my_hash_free(&conf_hash); + } +} + +conf_param * +config::find(const String& key) const +{ + if (init) + return (conf_param *) my_hash_search(&conf_hash, (const uchar*) key.ptr(), + key.length()); + else + return NULL; +} + +conf_param * +config::find(const char *key) const +{ + if (init) + return (conf_param *) my_hash_search(&conf_hash, (const uchar*) key, + strlen(key)); + else + return NULL; +} + +String +config::get_str(const String& key, const String& def) const +{ + DENA_VERBOSE(30, list_all_params()); + conf_param *param = find(key); + if (!param) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(default)\n", key.ptr(), + def.ptr())); + return def; + } + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", key.ptr(), + param->val.ptr())); + return param->val; +} + +String +config::get_str(const char *key, const char *def) const +{ + DENA_VERBOSE(30, list_all_params()); + conf_param *param = find(key); + if (!param) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(default)\n", key, def)); + return String(def, strlen(def), &my_charset_bin); + } + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", + key, param->val.ptr())); + return param->val; +} + +long long +config::get_int(const String& key, long long def) const +{ + int err; + DENA_VERBOSE(30, list_all_params()); + conf_param *param = find(key); + if (!param) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(default)\n", key.ptr(), + def)); + return def; + } + const long long r = my_strtoll10(param->val.ptr(), (char**) NULL, &err); + if (err) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(err)\n", key.ptr(), + def)); + return def; + } + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld\n", key.ptr(), r)); + return r; +} + +long long +config::get_int(const char *key, long long def) const +{ + int err; + DENA_VERBOSE(30, list_all_params()); + conf_param *param = find(key); + if (!param) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(default)\n", key, def)); + return def; + } + const long long r = my_strtoll10(param->val.ptr(), (char**) NULL, &err); + if (err) { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(err)\n", key, def)); + return def; + } + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld\n", key, r)); + return r; +} + +bool +config::replace(const char *key, const char *val) +{ + uint32 val_len = strlen(val); + conf_param *param = find(key); + if (!param) { + /* create */ + if (!(param = new conf_param())) + return TRUE; + uint32 key_len = strlen(key); + if ( + param->key.reserve(key_len + 1) || + param->val.reserve(val_len + 1) + ) { + delete param; + return TRUE; + } + param->key.q_append(key, key_len); + param->val.q_append(val, val_len); + param->key.c_ptr_safe(); + param->val.c_ptr_safe(); + if (my_hash_insert(&conf_hash, (uchar*) param)) + { + delete param; + return TRUE; + } + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(create)\n", + param->key.ptr(), param->val.ptr())); + return FALSE; + } + /* replace */ + param->val.length(0); + if (param->val.reserve(val_len + 1)) + return TRUE; + param->val.q_append(val, val_len); + param->val.c_ptr_safe(); + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(replace)\n", + param->key.ptr(), param->val.ptr())); + return FALSE; +} + +bool +config::replace(const char *key, long long val) +{ + char val_str[22]; + sprintf(val_str, "%lld", val); + return replace(key, val_str); +} + +bool +config::compare(const char *key, const char *val) +{ + conf_param *param = find(key); + if (!param) + return FALSE; + return !strcmp(param->val.ptr(), val); +} + +void +config::list_all_params() const +{ + conf_param *param; + DENA_VERBOSE(10, fprintf(stderr, "list_all_params start\n")); + for(ulong i = 0; i < conf_hash.records; i++) + { + if ((param = (conf_param *) my_hash_element((HASH *) &conf_hash, i))) + { + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", + param->key.ptr(), param->val.ptr())); + } + } + DENA_VERBOSE(10, fprintf(stderr, "list_all_params end\n")); +} + +config& +config::operator =(const config& x) +{ + DENA_VERBOSE(10, fprintf(stderr, "config operator = start")); + if (this != &x && init && x.init) { + conf_param *param, *new_param; + for(ulong i = 0; i < x.conf_hash.records; i++) + { + if ( + (param = (conf_param *) my_hash_element((HASH *) &x.conf_hash, i)) && + (new_param = new conf_param()) + ) { + if ( + !new_param->key.copy(param->key) && + !new_param->val.copy(param->val) + ) { + new_param->key.c_ptr_safe(); + new_param->val.c_ptr_safe(); + DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", + new_param->key.ptr(), new_param->val.ptr())); + if (my_hash_insert(&conf_hash, (uchar*) new_param)) + delete new_param; + } else + delete new_param; + } + } + } + DENA_VERBOSE(10, fprintf(stderr, "config operator = end %p", this)); + return *this; +} + +void +parse_args(int argc, char **argv, config& conf) +{ + conf_param *param; + for (int i = 1; i < argc; ++i) { + const char *const arg = argv[i]; + const char *const eq = strchr(arg, '='); + if (eq == 0) { + continue; + } + if (!(param = new conf_param())) + continue; + uint32 key_len = (uint32)(eq - arg); + uint32 val_len = strlen(eq + 1); + if ( + param->key.reserve(key_len + 1) || + param->val.reserve(val_len + 1) + ) { + delete param; + continue; + } + param->key.q_append(arg, key_len); + param->val.q_append(eq + 1, val_len); + param->key.c_ptr_safe(); + param->val.c_ptr_safe(); + if (my_hash_insert(&conf.conf_hash, (uchar*) param)) + { + delete param; + continue; + } + } + param = conf.find("verbose"); + if (param) { + verbose_level = atoi(param->val.c_ptr()); + } +} + +}; + diff --git a/storage/spider/hs_client/config.hpp b/storage/spider/hs_client/config.hpp new file mode 100644 index 00000000..2880f2f5 --- /dev/null +++ b/storage/spider/hs_client/config.hpp @@ -0,0 +1,81 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_CONFIG_HPP +#define DENA_CONFIG_HPP + +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#include "sql_class.h" +#endif + +#define DENA_VERBOSE(lv, x) if (dena::verbose_level >= (lv)) { (x); } + +#ifdef HANDLER_HAS_DIRECT_UPDATE_ROWS +#define INFO_KIND_HS_RET_FIELDS 1 +#define INFO_KIND_HS_APPEND_STRING_REF 3 +#define INFO_KIND_HS_CLEAR_STRING_REF 4 +#define INFO_KIND_HS_INCREMENT_BEGIN 5 +#define INFO_KIND_HS_INCREMENT_END 6 +#define INFO_KIND_HS_DECREMENT_BEGIN 7 +#define INFO_KIND_HS_DECREMENT_END 8 +#endif + +namespace dena { + +#ifdef HANDLER_HAS_DIRECT_UPDATE_ROWS +struct uint32_info { + size_t info_size; + uint32 *info; +}; +#endif + +struct conf_param { + String key; + String val; +}; + +uchar *conf_get_key( + conf_param *share, + size_t *length, + my_bool not_used __attribute__ ((unused)) +); + +struct config { + bool init; + HASH conf_hash; + config(); + ~config(); + conf_param *find(const String& key) const; + conf_param *find(const char *key) const; + String get_str(const String& key, const String& def = + String("", &my_charset_bin)) const; + String get_str(const char *key, const char *def = "") const; + long long get_int(const String& key, long long def = 0) const; + long long get_int(const char *key, long long def = 0) const; + bool replace(const char *key, const char *val); + bool replace(const char *key, long long val); + bool compare(const char *key, const char *val); + void list_all_params() const; + config& operator =(const config& x); +}; + +void parse_args(int argc, char **argv, config& conf); + +extern unsigned int verbose_level; + +}; + +#endif + diff --git a/storage/spider/hs_client/escape.cpp b/storage/spider/hs_client/escape.cpp new file mode 100644 index 00000000..f3e60afc --- /dev/null +++ b/storage/spider/hs_client/escape.cpp @@ -0,0 +1,129 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include "mysql_version.h" +#include "hs_compat.h" +#include "escape.hpp" +#include "string_buffer.hpp" +#include "fatal.hpp" +#include "string_util.hpp" + +#define DBG_OP(x) +#define DBG_BUF(x) + +namespace dena { + +enum special_char_t { + special_char_escape_prefix = 0x01, /* SOH */ + special_char_noescape_min = 0x10, /* DLE */ + special_char_escape_shift = 0x40, /* '@' */ +}; + +void +escape_string(char *& wp, const char *start, const char *finish) +{ + while (start != finish) { + const unsigned char c = *start; + if (c >= special_char_noescape_min) { + wp[0] = c; /* no need to escape */ + } else { + wp[0] = special_char_escape_prefix; + ++wp; + wp[0] = c + special_char_escape_shift; + } + ++start; + ++wp; + } +} + +void +escape_string(string_buffer& ar, const char *start, const char *finish) +{ + const size_t buflen = (finish - start) * 2; + char *const wp_begin = ar.make_space(buflen); + char *wp = wp_begin; + escape_string(wp, start, finish); + ar.space_wrote(wp - wp_begin); +} + +bool +unescape_string(char *& wp, const char *start, const char *finish) +{ + /* works even if wp == start */ + while (start != finish) { + const unsigned char c = *start; + if (c != special_char_escape_prefix) { + wp[0] = c; + } else if (start + 1 != finish) { + ++start; + const unsigned char cn = *start; + if (cn < special_char_escape_shift) { + return false; + } + wp[0] = cn - special_char_escape_shift; + } else { + return false; + } + ++start; + ++wp; + } + return true; +} + +bool +unescape_string(string_buffer& ar, const char *start, const char *finish) +{ + const size_t buflen = finish - start; + char *const wp_begin = ar.make_space(buflen); + char *wp = wp_begin; + const bool r = unescape_string(wp, start, finish); + ar.space_wrote(wp - wp_begin); + return r; +} + +uint32 +read_ui32(char *& start, char *finish) +{ + char *const n_begin = start; + read_token(start, finish); + char *const n_end = start; + uint32 v = 0; + for (char *p = n_begin; p != n_end; ++p) { + const char ch = p[0]; + if (ch >= '0' && ch <= '9') { + v *= 10; + v += (ch - '0'); + } + } + return v; +} + +void +write_ui32(string_buffer& buf, uint32 v) +{ + char *wp = buf.make_space(12); + int len = snprintf(wp, 12, "%u", v); + if (len > 0) { + buf.space_wrote(len); + } +} + +void +write_ui64(string_buffer& buf, uint64 v) +{ + char *wp = buf.make_space(22); + int len = snprintf(wp, 22, "%llu", static_cast<unsigned long long>(v)); + if (len > 0) { + buf.space_wrote(len); + } +} + +}; + diff --git a/storage/spider/hs_client/escape.hpp b/storage/spider/hs_client/escape.hpp new file mode 100644 index 00000000..4c23e167 --- /dev/null +++ b/storage/spider/hs_client/escape.hpp @@ -0,0 +1,64 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. + * See COPYRIGHT.txt for details. + */ + +#include "string_buffer.hpp" +#include "string_ref.hpp" +#include "string_util.hpp" + +#ifndef DENA_ESCAPE_HPP +#define DENA_ESCAPE_HPP + +namespace dena { + +void escape_string(char *& wp, const char *start, const char *finish); +void escape_string(string_buffer& ar, const char *start, const char *finish); +bool unescape_string(char *& wp, const char *start, const char *finish); + /* unescaped_string() works even if wp == start */ +bool unescape_string(string_buffer& ar, const char *start, const char *finish); + +uint32 read_ui32(char *& start, char *finish); +void write_ui32(string_buffer& buf, uint32 v); +void write_ui64(string_buffer& buf, uint64 v); + +inline bool +is_null_expression(const char *start, const char *finish) +{ + return (finish == start + 1 && start[0] == 0); +} + +inline void +read_token(char *& start, char *finish) +{ + char *const p = memchr_char(start, '\t', finish - start); + if (p == 0) { + start = finish; + } else { + start = p; + } +} + +inline void +skip_token_delim_fold(char *& start, char *finish) +{ + while (start != finish && start[0] == '\t') { + ++start; + } +} + +inline void +skip_one(char *& start, char *finish) +{ + if (start != finish) { + ++start; + } +} + +}; + +#endif + diff --git a/storage/spider/hs_client/fatal.cpp b/storage/spider/hs_client/fatal.cpp new file mode 100644 index 00000000..cfbc14df --- /dev/null +++ b/storage/spider/hs_client/fatal.cpp @@ -0,0 +1,49 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "fatal.hpp" + +namespace dena { + +/* +const int opt_syslog = LOG_ERR | LOG_PID | LOG_CONS; +*/ + +void +fatal_abort(const String& message) +{ + fprintf(stderr, "FATAL_COREDUMP: %s\n", message.ptr()); +/* + syslog(opt_syslog, "FATAL_COREDUMP: %s", message.ptr()); +*/ + abort(); +} + +void +fatal_abort(const char *message) +{ + fprintf(stderr, "FATAL_COREDUMP: %s\n", message); +/* + syslog(opt_syslog, "FATAL_COREDUMP: %s", message); +*/ + abort(); +} + +}; + diff --git a/storage/spider/hs_client/fatal.hpp b/storage/spider/hs_client/fatal.hpp new file mode 100644 index 00000000..38fc149e --- /dev/null +++ b/storage/spider/hs_client/fatal.hpp @@ -0,0 +1,31 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_FATAL_HPP +#define DENA_FATAL_HPP + +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#include "sql_class.h" +#endif + +namespace dena { + +void fatal_abort(const String& message); +void fatal_abort(const char *message); + +}; + +#endif + diff --git a/storage/spider/hs_client/hs_compat.h b/storage/spider/hs_client/hs_compat.h new file mode 100644 index 00000000..fb9b02ad --- /dev/null +++ b/storage/spider/hs_client/hs_compat.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2018 Kentoku Shiba + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#ifndef HS_COMPAT_H +#define HS_COMPAT_H + +#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100500 +#define SPD_INIT_DYNAMIC_ARRAY2(A, B, C, D, E, F) \ + my_init_dynamic_array2(PSI_INSTRUMENT_ME, A, B, C, D, E, F) +#define SPD_INIT_ALLOC_ROOT(A, B, C, D) \ + init_alloc_root(PSI_INSTRUMENT_ME, A, B, C, D) +#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100213 +#define SPD_INIT_DYNAMIC_ARRAY2(A, B, C, D, E, F) \ + my_init_dynamic_array2(A, B, C, D, E, F) +#define SPD_INIT_ALLOC_ROOT(A, B, C, D) \ + init_alloc_root(A, "spider", B, C, D) +#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100000 +#define SPD_INIT_DYNAMIC_ARRAY2(A, B, C, D, E, F) \ + my_init_dynamic_array2(A, B, C, D, E, F) +#define SPD_INIT_ALLOC_ROOT(A, B, C, D) \ + init_alloc_root(A, B, C, D) +#else +#define SPD_INIT_DYNAMIC_ARRAY2(A, B, C, D, E, F) \ + my_init_dynamic_array2(A, B, C, D, E) +#define SPD_INIT_ALLOC_ROOT(A, B, C, D) \ + init_alloc_root(A, B, C) +#endif + +#endif diff --git a/storage/spider/hs_client/hstcpcli.cpp b/storage/spider/hs_client/hstcpcli.cpp new file mode 100644 index 00000000..4c93b5a3 --- /dev/null +++ b/storage/spider/hs_client/hstcpcli.cpp @@ -0,0 +1,667 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include "mysql_version.h" +#include "hs_compat.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#include "sql_class.h" +#endif + +#include "hstcpcli.hpp" +#include "auto_file.hpp" +#include "string_util.hpp" +#include "auto_addrinfo.hpp" +#include "escape.hpp" +#include "util.hpp" + +/* TODO */ +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL 0 +#endif + +#define DBG(x) + +namespace dena { + +hstresult::hstresult() +{ + SPD_INIT_DYNAMIC_ARRAY2(&flds, sizeof(string_ref), NULL, 16, 16, + MYF(MY_WME)); +} + +hstresult::~hstresult() +{ + delete_dynamic(&flds); +} + +struct hstcpcli : public hstcpcli_i, private noncopyable { + hstcpcli(const socket_args& args); + virtual ~hstcpcli(); + virtual void close(); + virtual int reconnect(); + virtual bool stable_point(); + virtual void request_buf_open_index(size_t pst_id, const char *dbn, + const char *tbl, const char *idx, const char *retflds, const char *filflds); + virtual void request_buf_auth(const char *secret, const char *typ); + virtual void request_buf_exec_generic(size_t pst_id, const string_ref& op, + const string_ref *kvs, size_t kvslen, uint32 limit, uint32 skip, + const string_ref& mod_op, const string_ref *mvs, size_t mvslen, + const hstcpcli_filter *fils, size_t filslen, int invalues_keypart, + const string_ref *invalues, size_t invalueslen); + virtual size_t request_buf_append(const char *start, const char *finish); + virtual void request_reset(); + virtual int request_send(); + virtual int response_recv(size_t& num_flds_r); + virtual int get_result(hstresult& result); + virtual const string_ref *get_next_row(); + virtual const string_ref *get_next_row_from_result(hstresult& result); + virtual size_t get_row_size(); + virtual size_t get_row_size_from_result(hstresult& result); + virtual void response_buf_remove(); + virtual int get_error_code(); + virtual String& get_error(); + virtual void clear_error(); + virtual int set_timeout(int send_timeout, int recv_timeout); + virtual size_t get_num_req_bufd() { return num_req_bufd; } + virtual size_t get_num_req_sent() { return num_req_sent; } + virtual size_t get_num_req_rcvd() { return num_req_rcvd; } + virtual size_t get_response_end_offset() { return response_end_offset; } + virtual const char *get_readbuf_begin() { return readbuf.begin(); } + virtual const char *get_readbuf_end() { return readbuf.end(); } + virtual const char *get_writebuf_begin() { return writebuf.begin(); } + virtual size_t get_writebuf_size() { return writebuf.size(); } + virtual void write_error_to_log(const char *func_name, const char *file_name, + ulong line_no); + private: + int read_more(); + int set_error(int code, const String& str); + int set_error(int code, const char *str); + private: + auto_file fd; + socket_args sargs; + string_buffer readbuf; + string_buffer writebuf; + size_t response_end_offset; /* incl newline */ + size_t cur_row_offset; + size_t cur_row_size; + size_t num_flds; + size_t num_req_bufd; /* buffered but not yet sent */ + size_t num_req_sent; /* sent but not yet received */ + size_t num_req_rcvd; /* received but not yet removed */ + int error_code; + String error_str; + DYNAMIC_ARRAY flds; + int errno_buf; +}; + +hstcpcli::hstcpcli(const socket_args& args) + : sargs(args), response_end_offset(0), cur_row_offset(0), cur_row_size(0), + num_flds(0), num_req_bufd(0), num_req_sent(0), num_req_rcvd(0), + error_code(0), errno_buf(0) +{ + String err; + SPD_INIT_DYNAMIC_ARRAY2(&flds, sizeof(string_ref), NULL, 16, 16, MYF(MY_WME)); + if (socket_connect(fd, sargs, err) != 0) { + set_error(-1, err); + } +} + +hstcpcli::~hstcpcli() +{ + delete_dynamic(&flds); +} + +void +hstcpcli::close() +{ + fd.close(); + readbuf.clear(); + writebuf.clear(); + response_end_offset = 0; + cur_row_offset = 0; + num_flds = 0; + num_req_bufd = 0; + num_req_sent = 0; + num_req_rcvd = 0; +} + +int +hstcpcli::reconnect() +{ + clear_error(); + close(); + String err; + if (socket_connect(fd, sargs, err) != 0) { + set_error(-1, err); + } + return error_code; +} + +int +hstcpcli::set_timeout(int send_timeout, int recv_timeout) +{ + String err; + sargs.send_timeout = send_timeout; + sargs.recv_timeout = recv_timeout; + if (socket_set_timeout(fd, sargs, err) != 0) { + set_error(-1, err); + } + return error_code; +} + +bool +hstcpcli::stable_point() +{ + /* returns true if cli can send a new request */ + return fd.get() >= 0 && num_req_bufd == 0 && num_req_sent == 0 && + num_req_rcvd == 0 && response_end_offset == 0; +} + +int +hstcpcli::get_error_code() +{ + return error_code; +} + +String& +hstcpcli::get_error() +{ + return error_str; +} + +int +hstcpcli::read_more() +{ + const size_t block_size = 4096; // FIXME + char *const wp = readbuf.make_space(block_size); + int rlen; + errno = 0; + while ((rlen = read(fd.get(), wp, block_size)) <= 0) { + errno_buf = errno; + if (rlen < 0) { + if (errno == EINTR || errno == EAGAIN) + { + errno = 0; + continue; + } + error_str = String("read: failed", &my_charset_bin); + } else { + error_str = String("read: eof", &my_charset_bin); + } + return rlen; + } + readbuf.space_wrote(rlen); + return rlen; +} + +void +hstcpcli::clear_error() +{ + DBG(fprintf(stderr, "CLEAR_ERROR: %d\n", error_code)); + error_code = 0; + error_str.length(0); +} + +int +hstcpcli::set_error(int code, const String& str) +{ + DBG(fprintf(stderr, "SET_ERROR: %d\n", code)); + error_code = code; + error_str = str; + return error_code; +} + +int +hstcpcli::set_error(int code, const char *str) +{ + uint32 str_len = strlen(str); + DBG(fprintf(stderr, "SET_ERROR: %d\n", code)); + error_code = code; + error_str.length(0); + if (error_str.reserve(str_len + 1)) + return 0; + error_str.q_append(str, str_len); + error_str.c_ptr_safe(); + return error_code; +} + +void +hstcpcli::request_buf_open_index(size_t pst_id, const char *dbn, + const char *tbl, const char *idx, const char *retflds, const char *filflds) +{ +/* + if (num_req_sent > 0 || num_req_rcvd > 0) { +*/ + if (num_req_rcvd > 0) { + close(); + set_error(-1, "request_buf_open_index: protocol out of sync"); + return; + } + const string_ref dbn_ref(dbn, strlen(dbn)); + const string_ref tbl_ref(tbl, strlen(tbl)); + const string_ref idx_ref(idx, strlen(idx)); + const string_ref rfs_ref(retflds, strlen(retflds)); + writebuf.append_literal("P\t"); + append_uint32(writebuf, pst_id); // FIXME size_t ? + writebuf.append_literal("\t"); + writebuf.append(dbn_ref.begin(), dbn_ref.end()); + writebuf.append_literal("\t"); + writebuf.append(tbl_ref.begin(), tbl_ref.end()); + writebuf.append_literal("\t"); + writebuf.append(idx_ref.begin(), idx_ref.end()); + writebuf.append_literal("\t"); + writebuf.append(rfs_ref.begin(), rfs_ref.end()); + if (filflds != 0) { + const string_ref fls_ref(filflds, strlen(filflds)); + writebuf.append_literal("\t"); + writebuf.append(fls_ref.begin(), fls_ref.end()); + } + writebuf.append_literal("\n"); + ++num_req_bufd; +} + +void +hstcpcli::request_buf_auth(const char *secret, const char *typ) +{ +/* + if (num_req_sent > 0 || num_req_rcvd > 0) { +*/ + if (num_req_rcvd > 0) { + close(); + set_error(-1, "request_buf_auth: protocol out of sync"); + return; + } + if (typ == 0) { + typ = "1"; + } + const string_ref typ_ref(typ, strlen(typ)); + const string_ref secret_ref(secret, strlen(secret)); + writebuf.append_literal("A\t"); + writebuf.append(typ_ref.begin(), typ_ref.end()); + writebuf.append_literal("\t"); + writebuf.append(secret_ref.begin(), secret_ref.end()); + writebuf.append_literal("\n"); + ++num_req_bufd; +} + +namespace { + +void +append_delim_value(string_buffer& buf, const char *start, const char *finish) +{ + if (start == 0) { + /* null */ + const char t[] = "\t\0"; + buf.append(t, t + 2); + } else { + /* non-null */ + buf.append_literal("\t"); + escape_string(buf, start, finish); + } +} + +}; + +void +hstcpcli::request_buf_exec_generic(size_t pst_id, const string_ref& op, + const string_ref *kvs, size_t kvslen, uint32 limit, uint32 skip, + const string_ref& mod_op, const string_ref *mvs, size_t mvslen, + const hstcpcli_filter *fils, size_t filslen, int invalues_keypart, + const string_ref *invalues, size_t invalueslen) +{ +/* + if (num_req_sent > 0 || num_req_rcvd > 0) { +*/ + if (num_req_rcvd > 0) { + close(); + set_error(-1, "request_buf_exec_generic: protocol out of sync"); + return; + } + append_uint32(writebuf, pst_id); // FIXME size_t ? + writebuf.append_literal("\t"); + writebuf.append(op.begin(), op.end()); + writebuf.append_literal("\t"); + append_uint32(writebuf, kvslen); // FIXME size_t ? + for (size_t i = 0; i < kvslen; ++i) { + const string_ref& kv = kvs[i]; + append_delim_value(writebuf, kv.begin(), kv.end()); + } + if (limit != 0 || skip != 0 || invalues_keypart >= 0 || + mod_op.size() != 0 || filslen != 0) { + /* has more option */ + writebuf.append_literal("\t"); + append_uint32(writebuf, limit); // FIXME size_t ? + if (skip != 0 || invalues_keypart >= 0 || + mod_op.size() != 0 || filslen != 0) { + writebuf.append_literal("\t"); + append_uint32(writebuf, skip); // FIXME size_t ? + } + if (invalues_keypart >= 0) { + writebuf.append_literal("\t@\t"); + append_uint32(writebuf, invalues_keypart); + writebuf.append_literal("\t"); + append_uint32(writebuf, invalueslen); + for (size_t i = 0; i < invalueslen; ++i) { + const string_ref& s = invalues[i]; + append_delim_value(writebuf, s.begin(), s.end()); + } + } + for (size_t i = 0; i < filslen; ++i) { + const hstcpcli_filter& f = fils[i]; + writebuf.append_literal("\t"); + writebuf.append(f.filter_type.begin(), f.filter_type.end()); + writebuf.append_literal("\t"); + writebuf.append(f.op.begin(), f.op.end()); + writebuf.append_literal("\t"); + append_uint32(writebuf, f.ff_offset); + append_delim_value(writebuf, f.val.begin(), f.val.end()); + } + if (mod_op.size() != 0) { + writebuf.append_literal("\t"); + writebuf.append(mod_op.begin(), mod_op.end()); + for (size_t i = 0; i < mvslen; ++i) { + const string_ref& mv = mvs[i]; + append_delim_value(writebuf, mv.begin(), mv.end()); + } + } + } + writebuf.append_literal("\n"); + ++num_req_bufd; +} + +size_t +hstcpcli::request_buf_append(const char *start, const char *finish) +{ +/* + if (num_req_sent > 0 || num_req_rcvd > 0) { +*/ + if (num_req_rcvd > 0) { + close(); + set_error(-1, "request_buf_append: protocol out of sync"); + return 0; + } + const char *nl = start; + size_t num_req = 0; + while ((nl = memchr_char(nl, '\n', finish - nl))) { + if (nl == finish) + break; + num_req++; + nl++; + } + num_req++; + writebuf.append(start, finish); + if (*(finish - 1) != '\n') + writebuf.append_literal("\n"); + num_req_bufd += num_req; + return num_req; +} + +void +hstcpcli::request_reset() +{ + if (num_req_bufd) { + writebuf.erase_front(writebuf.size()); + num_req_bufd = 0; + } +} + +int +hstcpcli::request_send() +{ + if (error_code < 0) { + return error_code; + } + clear_error(); + if (fd.get() < 0) { + close(); + return set_error(-1, "write: closed"); + } +/* + if (num_req_bufd == 0 || num_req_sent > 0 || num_req_rcvd > 0) { +*/ + if (num_req_bufd == 0 || num_req_rcvd > 0) { + close(); + return set_error(-1, "request_send: protocol out of sync"); + } + const size_t wrlen = writebuf.size(); + const ssize_t r = send(fd.get(), writebuf.begin(), wrlen, MSG_NOSIGNAL); + if (r <= 0) { + close(); + return set_error(-1, r < 0 ? "write: failed" : "write: eof"); + } + writebuf.erase_front(r); + if (static_cast<size_t>(r) != wrlen) { + close(); + return set_error(-1, "write: incomplete"); + } + num_req_sent += num_req_bufd; + num_req_bufd = 0; + DBG(fprintf(stderr, "REQSEND 0\n")); + return 0; +} + +int +hstcpcli::response_recv(size_t& num_flds_r) +{ + if (error_code < 0) { + return error_code; + } + clear_error(); + if (num_req_bufd > 0 || num_req_sent == 0 || num_req_rcvd > 0 || + response_end_offset != 0) { + close(); + return set_error(-1, "response_recv: protocol out of sync"); + } + cur_row_offset = 0; + num_flds_r = num_flds = 0; + if (fd.get() < 0) { + return set_error(-1, "read: closed"); + } + size_t offset = 0; + while (true) { + const char *const lbegin = readbuf.begin() + offset; + const char *const lend = readbuf.end(); + if (lbegin < lend) + { + const char *const nl = memchr_char(lbegin, '\n', lend - lbegin); + if (nl != 0) { + offset += (nl + 1) - lbegin; + break; + } + offset += lend - lbegin; + } + if (read_more() <= 0) { + close(); + error_code = -1; + return error_code; + } + } + response_end_offset = offset; + --num_req_sent; + ++num_req_rcvd; + char *start = readbuf.begin(); + char *const finish = start + response_end_offset - 1; + const size_t resp_code = read_ui32(start, finish); + skip_one(start, finish); + num_flds_r = num_flds = read_ui32(start, finish); + if (resp_code != 0) { + skip_one(start, finish); + char *const err_begin = start; + read_token(start, finish); + char *const err_end = start; + String e = String(err_begin, (uint32)(err_end - err_begin), &my_charset_bin); + if (!e.length()) { + e = String("unknown_error", &my_charset_bin); + } + return set_error(resp_code, e); + } + cur_row_size = 0; + cur_row_offset = start - readbuf.begin(); + DBG(fprintf(stderr, "[%s] ro=%zu eol=%zu\n", + String(readbuf.begin(), readbuf.begin() + response_end_offset) + .c_str(), + cur_row_offset, response_end_offset)); + DBG(fprintf(stderr, "RES 0\n")); + if (flds.max_element < num_flds) + { + if (allocate_dynamic(&flds, num_flds)) + return set_error(-1, "out of memory"); + } + flds.elements = num_flds; + return 0; +} + +int +hstcpcli::get_result(hstresult& result) +{ +/* + readbuf.swap(result.readbuf); +*/ + char *const wp = result.readbuf.make_space(response_end_offset); + memcpy(wp, readbuf.begin(), response_end_offset); + result.readbuf.space_wrote(response_end_offset); + result.response_end_offset = response_end_offset; + result.num_flds = num_flds; + result.cur_row_size = cur_row_size; + result.cur_row_offset = cur_row_offset; + if (result.flds.max_element < num_flds) + { + if (allocate_dynamic(&result.flds, num_flds)) + return set_error(-1, "out of memory"); + } + result.flds.elements = num_flds; + return 0; +} + +const string_ref * +hstcpcli::get_next_row() +{ + if (num_flds == 0 || flds.elements < num_flds) { + DBG(fprintf(stderr, "GNR NF 0\n")); + return 0; + } + char *start = readbuf.begin() + cur_row_offset; + char *const finish = readbuf.begin() + response_end_offset - 1; + if (start >= finish) { /* start[0] == nl */ + DBG(fprintf(stderr, "GNR FIN 0 %p %p\n", start, finish)); + return 0; + } + for (size_t i = 0; i < num_flds; ++i) { + skip_one(start, finish); + char *const fld_begin = start; + read_token(start, finish); + char *const fld_end = start; + char *wp = fld_begin; + if (is_null_expression(fld_begin, fld_end)) { + /* null */ + ((string_ref *) flds.buffer)[i] = string_ref(); + } else { + unescape_string(wp, fld_begin, fld_end); /* in-place */ + ((string_ref *) flds.buffer)[i] = string_ref(fld_begin, wp); + } + } + cur_row_size = start - (readbuf.begin() + cur_row_offset); + cur_row_offset = start - readbuf.begin(); + return (string_ref *) flds.buffer; +} + +const string_ref * +hstcpcli::get_next_row_from_result(hstresult& result) +{ + if (result.num_flds == 0 || result.flds.elements < result.num_flds) { + DBG(fprintf(stderr, "GNR NF 0\n")); + return 0; + } + char *start = result.readbuf.begin() + result.cur_row_offset; + char *const finish = result.readbuf.begin() + result.response_end_offset - 1; + if (start >= finish) { /* start[0] == nl */ + DBG(fprintf(stderr, "GNR FIN 0 %p %p\n", start, finish)); + return 0; + } + for (size_t i = 0; i < result.num_flds; ++i) { + skip_one(start, finish); + char *const fld_begin = start; + read_token(start, finish); + char *const fld_end = start; + char *wp = fld_begin; + if (is_null_expression(fld_begin, fld_end)) { + /* null */ + ((string_ref *) result.flds.buffer)[i] = string_ref(); + } else { + unescape_string(wp, fld_begin, fld_end); /* in-place */ + ((string_ref *) result.flds.buffer)[i] = string_ref(fld_begin, wp); + } + } + result.cur_row_size = + start - (result.readbuf.begin() + result.cur_row_offset); + result.cur_row_offset = start - result.readbuf.begin(); + return (string_ref *) result.flds.buffer; +} + +size_t +hstcpcli::get_row_size() +{ + return cur_row_size; +} + +size_t +hstcpcli::get_row_size_from_result(hstresult& result) +{ + return result.cur_row_size; +} + +void +hstcpcli::response_buf_remove() +{ + if (response_end_offset == 0) { + close(); + set_error(-1, "response_buf_remove: protocol out of sync"); + return; + } + readbuf.erase_front(response_end_offset); + response_end_offset = 0; + --num_req_rcvd; + cur_row_offset = 0; + num_flds = 0; +} + +void +hstcpcli::write_error_to_log( + const char *func_name, + const char *file_name, + ulong line_no +) { + if (errno_buf) { + time_t cur_time = (time_t) time((time_t*) 0); + struct tm lt; + struct tm *l_time = localtime_r(&cur_time, <); + fprintf(stderr, + "%04d%02d%02d %02d:%02d:%02d [ERROR] hstcpcli: [%d][%s]" + " [%s][%s][%lu] errno=%d\n", + l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday, + l_time->tm_hour, l_time->tm_min, l_time->tm_sec, + error_code, error_str.c_ptr_safe(), + func_name, file_name, line_no, errno_buf); + } +} + +hstcpcli_ptr +hstcpcli_i::create(const socket_args& args) +{ + return hstcpcli_ptr(new hstcpcli(args)); +} + +}; + diff --git a/storage/spider/hs_client/hstcpcli.hpp b/storage/spider/hs_client/hstcpcli.hpp new file mode 100644 index 00000000..6894716e --- /dev/null +++ b/storage/spider/hs_client/hstcpcli.hpp @@ -0,0 +1,98 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_HSTCPCLI_HPP +#define DENA_HSTCPCLI_HPP + +#define HANDLERSOCKET_MYSQL_UTIL 1 + +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "config.hpp" +#include "socket.hpp" +#include "string_ref.hpp" +#include "string_buffer.hpp" + +namespace dena { + +struct hstcpcli_filter { + string_ref filter_type; + string_ref op; + size_t ff_offset; + string_ref val; + hstcpcli_filter() : ff_offset(0) { } +}; + +struct hstcpcli_i; +typedef hstcpcli_i *hstcpcli_ptr; + +struct hstresult { + hstresult(); + virtual ~hstresult(); + string_buffer readbuf; + size_t response_end_offset; + size_t num_flds; + size_t cur_row_offset; + size_t cur_row_size; + DYNAMIC_ARRAY flds; +}; + +struct hstcpcli_i { + virtual ~hstcpcli_i() { } + virtual void close() = 0; + virtual int reconnect() = 0; + virtual bool stable_point() = 0; + virtual void request_buf_auth(const char *secret, const char *typ) = 0; + virtual void request_buf_open_index(size_t pst_id, const char *dbn, + const char *tbl, const char *idx, const char *retflds, + const char *filflds = 0) = 0; + virtual void request_buf_exec_generic(size_t pst_id, const string_ref& op, + const string_ref *kvs, size_t kvslen, uint32 limit, uint32 skip, + const string_ref& mod_op, const string_ref *mvs, size_t mvslen, + const hstcpcli_filter *fils = 0, size_t filslen = 0, + int invalues_keypart = -1, const string_ref *invalues = 0, + size_t invalueslen = 0) = 0; // FIXME: too long + virtual size_t request_buf_append(const char *start, const char *finish) = 0; + virtual void request_reset() = 0; + virtual int request_send() = 0; + virtual int response_recv(size_t& num_flds_r) = 0; + virtual int get_result(hstresult& result) = 0; + virtual const string_ref *get_next_row() = 0; + virtual const string_ref *get_next_row_from_result(hstresult& result) = 0; + virtual size_t get_row_size() = 0; + virtual size_t get_row_size_from_result(hstresult& result) = 0; + virtual void response_buf_remove() = 0; + virtual int get_error_code() = 0; + virtual String& get_error() = 0; + virtual void clear_error() = 0; + virtual int set_timeout(int send_timeout, int recv_timeout) = 0; + virtual size_t get_num_req_bufd() = 0; + virtual size_t get_num_req_sent() = 0; + virtual size_t get_num_req_rcvd() = 0; + virtual size_t get_response_end_offset() = 0; + virtual const char *get_readbuf_begin() = 0; + virtual const char *get_readbuf_end() = 0; + virtual const char *get_writebuf_begin() = 0; + virtual size_t get_writebuf_size() = 0; + virtual void write_error_to_log(const char *func_name, const char *file_name, + ulong line_no) = 0; + static hstcpcli_ptr create(const socket_args& args); +}; + +}; + +#endif + diff --git a/storage/spider/hs_client/mutex.hpp b/storage/spider/hs_client/mutex.hpp new file mode 100644 index 00000000..8e331fb6 --- /dev/null +++ b/storage/spider/hs_client/mutex.hpp @@ -0,0 +1,48 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_MUTEX_HPP +#define DENA_MUTEX_HPP + +#include "fatal.hpp" +#include "util.hpp" + +namespace dena { + +struct condition; + +struct mutex : private noncopyable { + friend struct condition; + mutex() { + if (pthread_mutex_init(&mtx, 0) != 0) { + fatal_abort("pthread_mutex_init"); + } + } + ~mutex() { + if (pthread_mutex_destroy(&mtx) != 0) { + fatal_abort("pthread_mutex_destroy"); + } + } + void lock() const { + if (pthread_mutex_lock(&mtx) != 0) { + fatal_abort("pthread_mutex_lock"); + } + } + void unlock() const { + if (pthread_mutex_unlock(&mtx) != 0) { + fatal_abort("pthread_mutex_unlock"); + } + } + private: + mutable pthread_mutex_t mtx; +}; + +}; + +#endif + diff --git a/storage/spider/hs_client/socket.cpp b/storage/spider/hs_client/socket.cpp new file mode 100644 index 00000000..45b8100e --- /dev/null +++ b/storage/spider/hs_client/socket.cpp @@ -0,0 +1,313 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include <my_config.h> +#ifndef __WIN__ +#include <sys/types.h> +#include <sys/un.h> +#endif + +#include "mysql_version.h" +#include "hs_compat.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100000 +#include <my_global.h> +#endif +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "socket.hpp" +#include "string_util.hpp" +#include "fatal.hpp" + +/* +struct sockaddr_un { + short sun_family; + char sun_path[108]; +}; +*/ + +namespace dena { + +void +ignore_sigpipe() +{ +#if defined(SIGPIPE) && !defined(__WIN__) + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + fatal_abort("SIGPIPE SIG_IGN"); + } +#endif +} + +void +socket_args::set(const config& conf) +{ + timeout = (int) conf.get_int("timeout", 600); + listen_backlog = (int) conf.get_int("listen_backlog", 256); + String node = conf.get_str("host", ""); + String port = conf.get_str("port", ""); + if (node.length() || port.length()) { + if (family == AF_UNIX || !strcmp(node.c_ptr(), "/")) { + set_unix_domain(port.c_ptr()); + } else { + const char *nd = !node.length() ? 0 : node.c_ptr(); + if (resolve(nd, port.c_ptr()) != 0) { + String message("getaddrinfo failed: ", &my_charset_bin); + message.reserve(node.length() + sizeof(":") - 1 + port.length()); + message.append(node); + message.q_append(":", sizeof(":") - 1); + message.append(port); + fatal_abort(message); + } + } + } + sndbuf = (int) conf.get_int("sndbuf", 0); + rcvbuf = (int) conf.get_int("rcvbuf", 0); +} + +void +socket_args::set_unix_domain(const char *path) +{ +#ifndef __WIN__ + family = AF_UNIX; + addr = sockaddr_storage(); + addrlen = sizeof(sockaddr_un); + sockaddr_un *const ap = reinterpret_cast<sockaddr_un *>(&addr); + ap->sun_family = AF_UNIX; + strncpy(ap->sun_path, path, sizeof(ap->sun_path) - 1); +#endif +} + +int +socket_args::resolve(const char *node, const char *service) +{ + const int flags = (node == 0) ? AI_PASSIVE : 0; + auto_addrinfo ai; + addr = sockaddr_storage(); + addrlen = 0; + const int r = ai.resolve(node, service, flags, family, socktype, protocol); + if (r != 0) { + return r; + } + memcpy(&addr, ai.get()->ai_addr, ai.get()->ai_addrlen); + addrlen = ai.get()->ai_addrlen; + return 0; +} + +int +socket_set_timeout(auto_file& fd, const socket_args& args, String& err_r) +{ + if (!args.nonblocking) { +#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) + if (args.recv_timeout != 0) { +#ifndef __WIN__ + struct timeval tv; + tv.tv_sec = args.recv_timeout; + tv.tv_usec = 0; +#else + int tv = args.recv_timeout * 1000; +#endif + if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, +#ifndef __WIN__ + (const void *) &tv, +#else + (const char *) &tv, +#endif + sizeof(tv)) != 0) { + return errno_string("setsockopt SO_RCVTIMEO", errno, err_r); + } + } + if (args.send_timeout != 0) { +#ifndef __WIN__ + struct timeval tv; + tv.tv_sec = args.send_timeout; + tv.tv_usec = 0; +#else + int tv = args.send_timeout * 1000; +#endif + if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, +#ifndef __WIN__ + (const void *) &tv, +#else + (const char *) &tv, +#endif + sizeof(tv)) != 0) { + return errno_string("setsockopt SO_SNDTIMEO", errno, err_r); + } + } +#endif + } + return 0; +} + +int +socket_set_options(auto_file& fd, const socket_args& args, String& err_r) +{ + if (args.timeout != 0 && !args.nonblocking) { +#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) +#ifndef __WIN__ + struct timeval tv; + tv.tv_sec = args.timeout; + tv.tv_usec = 0; +#else + int tv = args.timeout * 1000; +#endif + if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, +#ifndef __WIN__ + (const void *) &tv, +#else + (const char *) &tv, +#endif + sizeof(tv)) != 0) { + return errno_string("setsockopt SO_RCVTIMEO", errno, err_r); + } +#ifndef __WIN__ + tv.tv_sec = args.timeout; + tv.tv_usec = 0; +#else + tv = args.timeout * 1000; +#endif + if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, +#ifndef __WIN__ + (const void *) &tv, +#else + (const char *) &tv, +#endif + sizeof(tv)) != 0) { + return errno_string("setsockopt SO_RCVTIMEO", errno, err_r); + } +#endif + } +#ifndef __WIN__ + if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { + return errno_string("fcntl O_NONBLOCK", errno, err_r); + } +#endif + if (args.sndbuf != 0) { + const int v = args.sndbuf; + if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDBUF, +#ifndef __WIN__ + (const void *) &v, +#else + (const char *) &v, +#endif + sizeof(v)) != 0) { + return errno_string("setsockopt SO_SNDBUF", errno, err_r); + } + } + if (args.rcvbuf != 0) { + const int v = args.rcvbuf; + if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, +#ifndef __WIN__ + (const void *) &v, +#else + (const char *) &v, +#endif + sizeof(v)) != 0) { + return errno_string("setsockopt SO_RCVBUF", errno, err_r); + } + } + return 0; +} + +int +socket_open(auto_file& fd, const socket_args& args, String& err_r) +{ + fd.reset((int) socket(args.family, args.socktype, args.protocol)); + if (fd.get() < 0) { + return errno_string("socket", errno, err_r); + } + return socket_set_options(fd, args, err_r); +} + +int +socket_connect(auto_file& fd, const socket_args& args, String& err_r) +{ + int r = 0; + if ((r = socket_open(fd, args, err_r)) != 0) { + return r; + } + if (connect(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr), + args.addrlen) != 0) { + if (!args.nonblocking +#ifndef __WIN__ + || errno != EINPROGRESS +#endif + ) { + return errno_string("connect", errno, err_r); + } + } + return 0; +} + +int +socket_bind(auto_file& fd, const socket_args& args, String& err_r) +{ + fd.reset((int) socket(args.family, args.socktype, args.protocol)); + if (fd.get() < 0) { + return errno_string("socket", errno, err_r); + } + if (args.reuseaddr) { +#ifndef __WIN__ + if (args.family == AF_UNIX) { + const sockaddr_un *const ap = + reinterpret_cast<const sockaddr_un *>(&args.addr); + if (unlink(ap->sun_path) != 0 && errno != ENOENT) { + return errno_string("unlink uds", errno, err_r); + } + } else { +#endif + int v = 1; + if (setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, +#ifndef __WIN__ + (const void *) &v, +#else + (const char *) &v, +#endif + sizeof(v)) != 0) { + return errno_string("setsockopt SO_REUSEADDR", errno, err_r); + } +#ifndef __WIN__ + } +#endif + } + if (bind(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr), + args.addrlen) != 0) { + return errno_string("bind", errno, err_r); + } + if (listen(fd.get(), args.listen_backlog) != 0) { + return errno_string("listen", errno, err_r); + } +#ifndef __WIN__ + if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { + return errno_string("fcntl O_NONBLOCK", errno, err_r); + } +#endif + return 0; +} + +int +socket_accept(int listen_fd, auto_file& fd, const socket_args& args, + sockaddr_storage& addr_r, socklen_t& addrlen_r, String& err_r) +{ + fd.reset((int) accept(listen_fd, reinterpret_cast<sockaddr *>(&addr_r), + &addrlen_r)); + if (fd.get() < 0) { + return errno_string("accept", errno, err_r); + } + return socket_set_options(fd, args, err_r); +} + +}; + diff --git a/storage/spider/hs_client/socket.hpp b/storage/spider/hs_client/socket.hpp new file mode 100644 index 00000000..a3e6527a --- /dev/null +++ b/storage/spider/hs_client/socket.hpp @@ -0,0 +1,62 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_SOCKET_HPP +#define DENA_SOCKET_HPP + +#include "mysql_version.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "auto_addrinfo.hpp" +#include "auto_file.hpp" +#include "config.hpp" + +namespace dena { + +struct socket_args { + sockaddr_storage addr; + socklen_t addrlen; + int family; + int socktype; + int protocol; + int timeout; + int send_timeout; + int recv_timeout; + int listen_backlog; + bool reuseaddr; + bool nonblocking; + bool use_epoll; + int sndbuf; + int rcvbuf; + socket_args() : addr(), addrlen(0), family(AF_INET), socktype(SOCK_STREAM), + protocol(0), timeout(600), send_timeout(600), recv_timeout(600), + listen_backlog(256), reuseaddr(true), nonblocking(false), use_epoll(false), + sndbuf(0), rcvbuf(0) { } + void set(const config& conf); + void set_unix_domain(const char *path); + int resolve(const char *node, const char *service); +}; + +void ignore_sigpipe(); +int socket_set_timeout(auto_file& fd, const socket_args& args, String& err_r); +int socket_bind(auto_file& fd, const socket_args& args, String& err_r); +int socket_connect(auto_file& fd, const socket_args& args, String& err_r); +int socket_accept(int listen_fd, auto_file& fd, const socket_args& args, + sockaddr_storage& addr_r, socklen_t& addrlen_r, String& err_r); + +}; + +#endif + diff --git a/storage/spider/hs_client/string_buffer.hpp b/storage/spider/hs_client/string_buffer.hpp new file mode 100644 index 00000000..c9a60748 --- /dev/null +++ b/storage/spider/hs_client/string_buffer.hpp @@ -0,0 +1,146 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_STRING_BUFFER_HPP +#define DENA_STRING_BUFFER_HPP + +/* +#include <stdlib.h> +#include <string.h> +*/ + +#include "util.hpp" +#include "allocator.hpp" +#include "fatal.hpp" + +namespace dena { + +struct string_buffer : private noncopyable { + string_buffer() : buffer(0), begin_offset(0), end_offset(0), alloc_size(0) { } + ~string_buffer() { + real_free(); + } + void real_free() { + if (alloc_size) { + DENA_FREE(buffer); + buffer = 0; + begin_offset = 0; + end_offset = 0; + alloc_size = 0; + } + } + size_t real_size() { + return alloc_size; + } + const char *begin() const { + return buffer + begin_offset; + } + const char *end() const { + return buffer + end_offset; + } + char *begin() { + return buffer + begin_offset; + } + char *end() { + return buffer + end_offset; + } + size_t size() const { + return end_offset - begin_offset; + } + void clear() { + begin_offset = end_offset = 0; + } + void resize(size_t len) { + if (size() < len) { + reserve(len); + memset(buffer + end_offset, 0, len - size()); + } + end_offset = begin_offset + len; + } + void reserve(size_t len) { + if (alloc_size >= begin_offset + len) { + return; + } + size_t asz = alloc_size; + while (asz < begin_offset + len) { + if (asz == 0) { + asz = 16; + } + const size_t asz_n = asz << 1; + if (asz_n < asz) { + fatal_abort("string_buffer::resize() overflow"); + } + asz = asz_n; + } + void *const p = DENA_REALLOC(buffer, asz); + if (p == 0) { + fatal_abort("string_buffer::resize() realloc"); + } + buffer = static_cast<char *>(p); + alloc_size = asz; + } + void erase_front(size_t len) { + if (len >= size()) { + clear(); + } else { + begin_offset += len; + } + } + char *make_space(size_t len) { + reserve(size() + len); + return buffer + end_offset; + } + void space_wrote(size_t len) { + len = len < alloc_size - end_offset ? len : alloc_size - end_offset; + end_offset += len; + } + template <size_t N> + void append_literal(const char (& str)[N]) { + append(str, str + N - 1); + } + void append(const char *start, const char *finish) { + const size_t len = finish - start; + reserve(size() + len); + memcpy(buffer + end_offset, start, len); + end_offset += len; + } + void append_2(const char *s1, const char *f1, const char *s2, + const char *f2) { + const size_t l1 = f1 - s1; + const size_t l2 = f2 - s2; + reserve(end_offset + l1 + l2); + memcpy(buffer + end_offset, s1, l1); + memcpy(buffer + end_offset + l1, s2, l2); + end_offset += l1 + l2; + } + void swap(string_buffer& sb) { + char *tmp_buffer = buffer; + size_t tmp_begin_offset = begin_offset; + size_t tmp_end_offset = end_offset; + size_t tmp_alloc_size = alloc_size; + buffer = sb.buffer; + begin_offset = sb.begin_offset; + end_offset = sb.end_offset; + alloc_size = sb.alloc_size; + sb.buffer = tmp_buffer; + sb.begin_offset = tmp_begin_offset; + sb.end_offset = tmp_end_offset; + sb.alloc_size = tmp_alloc_size; + } + private: + char *buffer; + size_t begin_offset; + size_t end_offset; + size_t alloc_size; +}; + +}; + +#endif + diff --git a/storage/spider/hs_client/string_ref.hpp b/storage/spider/hs_client/string_ref.hpp new file mode 100644 index 00000000..028c4146 --- /dev/null +++ b/storage/spider/hs_client/string_ref.hpp @@ -0,0 +1,106 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_STRING_REF_HPP +#define DENA_STRING_REF_HPP + +namespace dena { + +struct string_wref { + typedef char value_type; + char *begin() const { return start; } + char *end() const { return start + length; } + size_t size() const { return length; } + private: + char *start; + size_t length; + public: + string_wref(char *s = 0, size_t len = 0) : start(s), length(len) { } +}; + +struct string_ref { + typedef const char value_type; + const char *begin() const { return start; } + const char *end() const { return start + length; } + size_t size() const { return length; } + void set(const char *s, size_t len) { start = s; length = len; } + void set(const char *s, const char *f) { start = s; length = f - s; } + private: + const char *start; + size_t length; + public: + string_ref(const char *s = 0, size_t len = 0) : start(s), length(len) { } + string_ref(const char *s, const char *f) : start(s), length(f - s) { } + string_ref(const string_wref& w) : start(w.begin()), length(w.size()) { } +}; + +template <size_t N> inline bool +operator ==(const string_ref& x, const char (& y)[N]) { + return (x.size() == N - 1) && (::memcmp(x.begin(), y, N - 1) == 0); +} + +inline bool +operator ==(const string_ref& x, const string_ref& y) { + return (x.size() == y.size()) && + (::memcmp(x.begin(), y.begin(), x.size()) == 0); +} + +inline bool +operator !=(const string_ref& x, const string_ref& y) { + return (x.size() != y.size()) || + (::memcmp(x.begin(), y.begin(), x.size()) != 0); +} + +struct string_ref_list_wrap { + string_ref_list_wrap() { + if (SPD_INIT_DYNAMIC_ARRAY2(&string_ref_list, sizeof(string_ref), + NULL, 16, 16, MYF(MY_WME))) + string_ref_list_init = FALSE; + else + string_ref_list_init = TRUE; + } + virtual ~string_ref_list_wrap() { + if (string_ref_list_init) delete_dynamic(&string_ref_list); } + void clear() { + if (string_ref_list_init) string_ref_list.elements = 0; } + void push_back(string_ref &e) { + if (string_ref_list_init) insert_dynamic(&string_ref_list, (uchar*) &e); + return; } + size_t size() { + return string_ref_list_init ? string_ref_list.elements : 0; } + bool resize(size_t new_size) { + if (string_ref_list_init) { + if (string_ref_list.max_element < new_size && allocate_dynamic( + &string_ref_list, new_size)) return TRUE; + string_ref_list.elements = new_size; + return FALSE; + } + return TRUE; + } + bool empty() { + return string_ref_list_init ? string_ref_list.elements ? + FALSE : TRUE : TRUE; } + string_ref &operator [](size_t n) { + return ((string_ref *) (string_ref_list.buffer + + string_ref_list.size_of_element * n))[0]; } + bool string_ref_list_init; + DYNAMIC_ARRAY string_ref_list; +}; + +inline String * +q_append_str(String *str, const char *p) { + uint32 p_len = strlen(p); + if (str->reserve(p_len)) return NULL; + str->q_append(p, p_len); return str; +} + +}; + +#endif + diff --git a/storage/spider/hs_client/string_util.cpp b/storage/spider/hs_client/string_util.cpp new file mode 100644 index 00000000..39934148 --- /dev/null +++ b/storage/spider/hs_client/string_util.cpp @@ -0,0 +1,207 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011-2017 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#include <my_global.h> +#include "mysql_version.h" +#include "hs_compat.h" +#if MYSQL_VERSION_ID < 50500 +#include "mysql_priv.h" +#include <mysql/plugin.h> +#else +#include "sql_priv.h" +#include "probes_mysql.h" +#endif + +#include "string_util.hpp" + +namespace dena { + +string_wref +get_token(char *& wp, char *wp_end, char delim) +{ + char *const wp_begin = wp; + char *const p = memchr_char(wp_begin, delim, wp_end - wp_begin); + if (p == 0) { + wp = wp_end; + return string_wref(wp_begin, wp_end - wp_begin); + } + wp = p + 1; + return string_wref(wp_begin, p - wp_begin); +} + +uint32 +atoi_uint32_nocheck(const char *start, const char *finish) +{ + uint32 v = 0; + for (; start != finish; ++start) { + const char c = *start; + if (c < '0' || c > '9') { + break; + } + v *= 10; + v += (uint32) (c - '0'); + } + return v; +} + +long long +atoll_nocheck(const char *start, const char *finish) +{ + long long v = 0; + bool negative = false; + if (start != finish) { + if (start[0] == '-') { + ++start; + negative = true; + } else if (start[0] == '+') { + ++start; + } + } + for (; start != finish; ++start) { + const char c = *start; + if (c < '0' || c > '9') { + break; + } + v *= 10; + if (negative) { + v -= (long long) (c - '0'); + } else { + v += (long long) (c - '0'); + } + } + return v; +} + +void +append_uint32(string_buffer& buf, uint32 v) +{ + char *const wp = buf.make_space(64); + const int len = snprintf(wp, 64, "%lu", static_cast<unsigned long>(v)); + if (len > 0) { + buf.space_wrote(len); + } +} + +/* +String * +to_stdstring(uint32 v) +{ + char buf[64]; + int str_len; + String *str; + str_len = snprintf(buf, sizeof(buf), "%lu", static_cast<unsigned long>(v)); + if ((str = new String(str_len + 1))) + str->q_append(buf, str_len); + return str; +} +*/ + +int +errno_string(const char *s, int en, String& err_r) +{ + char buf[64]; + int str_len; + str_len = snprintf(buf, sizeof(buf), "%s: %d", s, en); + if (!err_r.reserve(str_len + 1)) + err_r.q_append(buf, str_len); + return en; +} + +size_t +split(char delim, const string_ref& buf, string_ref *parts, + size_t parts_len) +{ + size_t i = 0; + const char *start = buf.begin(); + const char *const finish = buf.end(); + for (i = 0; i < parts_len; ++i) { + const char *const p = memchr_char(start, delim, finish - start); + if (p == 0) { + parts[i] = string_ref(start, finish - start); + ++i; + break; + } + parts[i] = string_ref(start, p - start); + start = p + 1; + } + const size_t r = i; + for (; i < parts_len; ++i) { + parts[i] = string_ref(); + } + return r; +} + +size_t +split(char delim, const string_wref& buf, string_wref *parts, + size_t parts_len) +{ + size_t i = 0; + char *start = buf.begin(); + char *const finish = buf.end(); + for (i = 0; i < parts_len; ++i) { + char *const p = memchr_char(start, delim, finish - start); + if (p == 0) { + parts[i] = string_wref(start, finish - start); + ++i; + break; + } + parts[i] = string_wref(start, p - start); + start = p + 1; + } + const size_t r = i; + for (; i < parts_len; ++i) { + parts[i] = string_wref(); + } + return r; +} + +size_t +split(char delim, const string_ref& buf, DYNAMIC_ARRAY& parts_r) +{ + size_t i = 0; + const char *start = buf.begin(); + const char *finish = buf.end(); + while (true) { + const char *p = memchr_char(start, delim, finish - start); + if (p == 0) { + string_ref param(start, finish - start); + insert_dynamic(&parts_r, (uchar *) ¶m); + break; + } + string_ref param(start, p - start); + insert_dynamic(&parts_r, (uchar *) ¶m); + start = p + 1; + } + const size_t r = i; + return r; +} + +size_t +split(char delim, const string_wref& buf, DYNAMIC_ARRAY& parts_r) +{ + size_t i = 0; + char *start = buf.begin(); + char *finish = buf.end(); + while (true) { + char *p = memchr_char(start, delim, finish - start); + if (p == 0) { + string_wref param(start, finish - start); + insert_dynamic(&parts_r, (uchar *) ¶m); + break; + } + string_wref param(start, p - start); + insert_dynamic(&parts_r, (uchar *) ¶m); + start = p + 1; + } + const size_t r = i; + return r; +} + +}; + diff --git a/storage/spider/hs_client/string_util.hpp b/storage/spider/hs_client/string_util.hpp new file mode 100644 index 00000000..b886adde --- /dev/null +++ b/storage/spider/hs_client/string_util.hpp @@ -0,0 +1,51 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_STRING_UTIL_HPP +#define DENA_STRING_UTIL_HPP + +#include "string_buffer.hpp" +#include "string_ref.hpp" + +namespace dena { + +inline const char * +memchr_char(const char *s, int c, size_t n) +{ + return static_cast<const char *>(memchr(s, c, n)); +} + +inline char * +memchr_char(char *s, int c, size_t n) +{ + return static_cast<char *>(memchr(s, c, n)); +} + +string_wref get_token(char *& wp, char *wp_end, char delim); +uint32 atoi_uint32_nocheck(const char *start, const char *finish); +/* +String *to_stdstring(uint32 v); +*/ +void append_uint32(string_buffer& buf, uint32 v); +long long atoll_nocheck(const char *start, const char *finish); + +int errno_string(const char *s, int en, String& err_r); + +size_t split(char delim, const string_ref& buf, string_ref *parts, + size_t parts_len); +size_t split(char delim, const string_wref& buf, string_wref *parts, + size_t parts_len); +size_t split(char delim, const string_ref& buf, + DYNAMIC_ARRAY& parts_r); +size_t split(char delim, const string_wref& buf, + DYNAMIC_ARRAY& parts_r); +}; + +#endif + diff --git a/storage/spider/hs_client/thread.hpp b/storage/spider/hs_client/thread.hpp new file mode 100644 index 00000000..79fba706 --- /dev/null +++ b/storage/spider/hs_client/thread.hpp @@ -0,0 +1,84 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved. + * Copyright (C) 2011 Kentoku SHIBA + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_THREAD_HPP +#define DENA_THREAD_HPP + +#include "fatal.hpp" + +namespace dena { + +/* +template <typename T> +struct thread : private noncopyable { + template <typename Ta> thread(const Ta& arg, size_t stack_sz = 256 * 1024) + : obj(arg), thr(0), need_join(false), stack_size(stack_sz) { } + template <typename Ta0, typename Ta1> thread(const Ta0& a0, + volatile Ta1& a1, size_t stack_sz = 256 * 1024) + : obj(a0, a1), thr(0), need_join(false), stack_size(stack_sz) { } + ~thread() { + join(); + } + void start() { + if (!start_nothrow()) { + fatal_abort("thread::start"); + } + } + bool start_nothrow() { + if (need_join) { + return need_join; + } + void *const arg = this; + pthread_attr_t attr; + if (pthread_attr_init(&attr) != 0) { + fatal_abort("pthread_attr_init"); + } + if (pthread_attr_setstacksize(&attr, stack_size) != 0) { + fatal_abort("pthread_attr_setstacksize"); + } + const int r = pthread_create(&thr, &attr, thread_main, arg); + if (pthread_attr_destroy(&attr) != 0) { + fatal_abort("pthread_attr_destroy"); + } + if (r != 0) { + return need_join; + } + need_join = true; + return need_join; + } + void join() { + if (!need_join) { + return; + } + int e = 0; + if ((e = pthread_join(thr, 0)) != 0) { + fatal_abort("pthread_join"); + } + need_join = false; + } + T& operator *() { return obj; } + T *operator ->() { return &obj; } + private: + static void *thread_main(void *arg) { + thread *p = static_cast<thread *>(arg); + p->obj(); + return 0; + } + private: + T obj; + pthread_t thr; + bool need_join; + size_t stack_size; +}; +*/ + +}; + +#endif + diff --git a/storage/spider/hs_client/util.hpp b/storage/spider/hs_client/util.hpp new file mode 100644 index 00000000..93d78cc7 --- /dev/null +++ b/storage/spider/hs_client/util.hpp @@ -0,0 +1,25 @@ + +// vim:sw=2:ai + +/* + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. + * See COPYRIGHT.txt for details. + */ + +#ifndef DENA_UTIL_HPP +#define DENA_UTIL_HPP + +namespace dena { + +/* boost::noncopyable */ +struct noncopyable { + noncopyable() { } + private: + noncopyable(const noncopyable&); + noncopyable& operator =(const noncopyable&); +}; + +}; + +#endif + |