Skip to content

Commit

Permalink
Add support for UNIX domain sockets (#120)
Browse files Browse the repository at this point in the history
* added support for UNIX domain sockets

* untested progress

* moved cython server string parse to c

* regression test for host parse

* updated cppcheck suppression

* golang bindings

* update c_client cppcheck

* removed duplicated line

* removed github workflow changes

* moved unix client to test_unix

* missed file

* remove atoi usage

* warning explanation

* removed unused cppcheck suppression

* startall for cython valgrind

* better string iteration

* sorry to commit after requesting review

* reverted server string parsing behavior

* code hygiene

* version bump

* syntax credit

* version bump not overwritten by pre-commit hook

* timezone matching email

* padding type

* fix port interpretation

* revert to existing distribution of responsibilities

* deduplicate golang test cases

* remove unnecessary inline in header

* rewrote to match default branch parsing more closely

* more descriptive names

* apt-get update before install
  • Loading branch information
kentslaney authored Dec 11, 2023
1 parent 9522d8a commit d32820f
Show file tree
Hide file tree
Showing 19 changed files with 260 additions and 70 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
- uses: actions/checkout@v2
- name: Setup system dependencies
run: |
sudo apt-get update
sudo apt-get -y install cppcheck
- name: Run cppcheck
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/golang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- uses: actions/checkout@v2
- name: Setup system dependencies
run: |
sudo apt-get update
sudo apt-get -y install memcached g++
- name: Set up Golang
uses: actions/setup-go@v2
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- uses: actions/checkout@v2
- name: Setup system dependencies
run: |
sudo apt-get update
sudo apt-get -y install valgrind memcached g++
- name: Set up Python
uses: actions/setup-python@v2
Expand All @@ -29,14 +30,14 @@ jobs:
python -m pip install --upgrade pip
pip install setuptools future pytest greenify gevent numpy
- name: Start memcached servers
run: ./misc/memcached_server start
run: ./misc/memcached_server startall
- name: Run unittest
run: |
if [[ ${{ matrix.compiler }} = "gcc" ]]; then export CC=gcc CXX=g++; fi
if [[ ${{ matrix.compiler }} = "clang" ]]; then export CC=clang CXX=clang++; fi
./misc/travis/unittest.sh
- name: Stop memcached servers
run: ./misc/memcached_server stop
run: ./misc/memcached_server stopall

benchmark:
runs-on: ubuntu-latest
Expand All @@ -48,6 +49,7 @@ jobs:
- uses: actions/checkout@v2
- name: Setup system dependencies
run: |
sudo apt-get update
sudo apt-get -y install memcached libmemcached-dev g++
- name: Set up Python
uses: actions/setup-python@v2
Expand Down
2 changes: 2 additions & 0 deletions include/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ typedef enum {
} op_code_t;

const char* errCodeToString(err_code_t err);
bool isLocalSocket(const char* host);
server_string_split_t splitServerString(char* input);

} // namespace mc
} // namespace douban
4 changes: 3 additions & 1 deletion include/Connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class Connection {
size_t m_counter;

protected:
int connectPoll(int fd, struct addrinfo* ai_ptr);
int connectPoll(int fd, const sockaddr* ai_ptr, const socklen_t ai_addrlen);
int unixSocketConnect();

char m_name[MC_NI_MAXHOST + 1 + MC_NI_MAXSERV];
char m_host[MC_NI_MAXHOST];
Expand All @@ -70,6 +71,7 @@ class Connection {
int m_socketFd;
bool m_alive;
bool m_hasAlias;
bool m_unixSocket;
time_t m_deadUntil;
io::BufferWriter* m_buffer_writer; // for send
io::BufferReader* m_buffer_reader; // for recv
Expand Down
6 changes: 6 additions & 0 deletions include/Export.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ typedef enum {
RET_OK = 0
} err_code_t;

typedef struct {
char* host;
char* port;
char* alias;
} server_string_split_t;


typedef int64_t exptime_t;
typedef uint32_t flags_t;
Expand Down
1 change: 1 addition & 0 deletions include/c_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extern "C" {
err_code_t client_quit(void* client);

const char* err_code_to_string(err_code_t err);
server_string_split_t splitServerString(char* input);
#ifdef __cplusplus
}
#endif
6 changes: 3 additions & 3 deletions libmc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
__file__ as _libmc_so_file
)

__VERSION__ = "1.4.2"
__version__ = "v1.4.2"
__VERSION__ = "1.4.3"
__version__ = "v1.4.3"
__author__ = "mckelvin"
__email__ = "[email protected]"
__date__ = "Thu May 20 18:44:42 2021 +0800"
__date__ = "Fri Dec 1 07:43:12 2023 +0800"


class Client(PyClient):
Expand Down
39 changes: 17 additions & 22 deletions libmc/_client.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ cdef extern from "Common.h" namespace "douban::mc":
VERSION_OP
QUIT_OP

server_string_split_t splitServerString(char* input) nogil


cdef extern from "Export.h":
ctypedef enum config_options_t:
Expand Down Expand Up @@ -99,6 +101,11 @@ cdef extern from "Export.h":
RET_INCOMPLETE_BUFFER_ERR
RET_OK

ctypedef struct server_string_split_t:
char* host
char* port
char* alias

ctypedef struct unsigned_result_t:
char* key
size_t key_len
Expand Down Expand Up @@ -378,33 +385,21 @@ cdef class PyClient:

servers_ = []
for srv in servers:
addr_alias = srv.split(' ')
addr = addr_alias[0]
if len(addr_alias) == 1:
alias = None
else:
alias = addr_alias[1]

host_port = addr.split(':')
host = host_port[0]
if len(host_port) == 1:
port = MC_DEFAULT_PORT
else:
port = int(host_port[1])
if PY_MAJOR_VERSION > 2:
host = PyUnicode_AsUTF8String(host)
alias = PyUnicode_AsUTF8String(alias) if alias else None
servers_.append((host, port, alias))
srv = PyUnicode_AsUTF8String(srv)
srv = PyString_AsString(srv)
servers_.append(srv)

Py_INCREF(servers_)
for i in range(n):
host, port, alias = servers_[i]
c_hosts[i] = PyString_AsString(host)
c_ports[i] = PyInt_AsLong(port)
if alias is None:
c_aliases[i] = NULL
c_split = splitServerString(servers_[i])

c_hosts[i] = c_split.host
c_aliases[i] = c_split.alias
if c_split.port == NULL:
c_ports[i] = MC_DEFAULT_PORT
else:
c_aliases[i] = PyString_AsString(alias)
c_ports[i] = PyInt_AsLong(int(<bytes>c_split.port))

if init:
rv = self._imp.init(c_hosts, c_ports, n, c_aliases)
Expand Down
4 changes: 2 additions & 2 deletions misc/.cppcheck-supp
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ unusedFunction:src/c_client.cpp:149
unusedFunction:src/c_client.cpp:154
unusedFunction:src/c_client.cpp:159
unusedFunction:src/Utility.cpp:43
*:src/Connection.cpp:30
*:src/Connection.cpp:35
*:src/Connection.cpp:32
*:src/Connection.cpp:37
35 changes: 34 additions & 1 deletion misc/memcached_server
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ function start()
fi
}

function unix()
{
name="${1:-unix_test}"
if [ ! -f $basedir/var/log/${name}.log ]; then
mkdir -p $basedir/var/log
touch $basedir/var/log/${name}.log
fi
mkdir -p $basedir/var/run
$cmd -d -u $USER -s $basedir/var/run/${name}.socket -t $threads -m ${memory} -P $basedir/var/run/${name}.pid > $basedir/var/log/${name}.log 2>&1
echo "Starting the memcached server on '$basedir/var/run/${name}.socket'... "
}

function stop()
{
port="$1"
Expand All @@ -41,7 +53,6 @@ function stop()
kill -TERM `ps -ef | grep "$cmd" | grep $port | grep -v grep | awk '{ print $2 }'`
echo "Stopping the memcached server on port '$port'... "
fi
rm -rf $basedir
}

case "$1" in
Expand All @@ -64,6 +75,7 @@ case "$1" in
stop $port &
done
wait
rm -rf $basedir
fi
;;
restart)
Expand All @@ -78,6 +90,27 @@ case "$1" in
wait
fi
;;
unix)
shift
unix $@
;;
startall)
unix &
for port in $PORTS; do
start $port &
done
wait
;;
stopall)
if [ `ls $basedir/var/run/ | grep -c .pid` -ge 1 ]; then
names="`basename $basedir/var/run/*.pid | cut -d. -f1`"
for name in $names; do
stop $name &
done
fi
wait
rm -rf $basedir
;;
*)
printf 'Usage: %s {start|stop|restart} <port>\n' "$prog"
exit 1
Expand Down
4 changes: 2 additions & 2 deletions misc/travis/cpptest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -ex

echo "CXX=${CXX}"
./misc/memcached_server start &>/dev/null &
./misc/memcached_server startall &>/dev/null &
python misc/generate_hash_dataset.py tests/resources/keys.txt &>/dev/null &
mkdir -p build
cd build
Expand All @@ -11,4 +11,4 @@ make -j8 &>/dev/null
wait
ARGS=-V make test
cd ..
./misc/memcached_server stop &>/dev/null &
./misc/memcached_server stopall &>/dev/null &
43 changes: 43 additions & 0 deletions src/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,48 @@ const char* errCodeToString(err_code_t err) {
}
}

bool isLocalSocket(const char* host) {
// errors on the side of false negatives, allowing syntax expansion;
// starting slash to denote socket paths is from pylibmc
return host[0] == '/';
}

// modifies input string and output pointers reference input
server_string_split_t splitServerString(char* input) {
bool escaped = false;
server_string_split_t res = { input, NULL, NULL };
for (;; input++) {
switch (*input)
{
case '\0':
return res;
case ':':
if (res.alias == NULL) {
*input = '\0';
if (res.port == NULL) {
res.port = input + 1;
}
}
escaped = false;
continue;
case ' ':
if (!escaped) {
*input = '\0';
if (res.alias == NULL) {
res.alias = input + 1;
continue;
} else {
return res;
}
}
default:
escaped = false;
continue;
case '\\':
escaped ^= 1;
}
}
}

} // namespace mc
} // namespace douban
Loading

0 comments on commit d32820f

Please sign in to comment.