195582c4183a81e19bb4131cf2f574dcd8d774e0
[awesomized/libmemcached] / src / libmemcached / quit.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 namespace {
19 memcached_return_t send_quit_message(memcached_instance_st *instance) {
20 memcached_return_t rc;
21 if (instance->root->flags.binary_protocol) {
22 protocol_binary_request_quit request = {}; // = {.bytes= {0}};
23
24 initialize_binary_request(instance, request.message.header);
25
26 request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
27 request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
28
29 libmemcached_io_vector_st vector[] = {{request.bytes, sizeof(request.bytes)}};
30
31 rc = memcached_vdo(instance, vector, 1, true);
32 } else {
33 libmemcached_io_vector_st vector[] = {{memcached_literal_param("quit\r\n")}};
34
35 rc = memcached_vdo(instance, vector, 1, true);
36 }
37
38 return rc;
39 }
40
41 void drain_instance(memcached_instance_st *instance) {
42 /* read until socket is closed, or there is an error
43 * closing the socket before all data is read
44 * results in server throwing away all data which is
45 * not read
46 *
47 * In .40 we began to only do this if we had been doing buffered
48 * requests of had replication enabled.
49 */
50 if (instance->root->flags.buffer_requests or instance->root->number_of_replicas) {
51 memcached_io_slurp(instance);
52 }
53
54 /*
55 * memcached_io_read may call memcached_quit_server with io_death if
56 * it encounters problems, but we don't care about those occurences.
57 * The intention of that loop is to drain the data sent from the
58 * server to ensure that the server processed all of the data we
59 * sent to the server.
60 */
61 instance->server_failure_counter = 0;
62 instance->server_timeout_counter = 0;
63 }
64 } // namespace
65
66 /*
67 This closes all connections (forces flush of input as well).
68
69 Maybe add a host specific, or key specific version?
70
71 The reason we send "quit" is that in case we have buffered IO, this
72 will force data to be completed.
73 */
74
75 void memcached_quit_server(memcached_instance_st *instance, bool io_death) {
76 if (instance->valid()) {
77 if (io_death == false and memcached_is_udp(instance->root) == false
78 and instance->is_shutting_down() == false)
79 {
80 send_quit_message(instance);
81
82 instance->start_close_socket();
83 drain_instance(instance);
84 }
85 }
86
87 instance->close_socket();
88
89 if (io_death and memcached_is_udp(instance->root)) {
90 /*
91 If using UDP, we should stop using the server briefly on every IO
92 failure. If using TCP, it may be that the connection went down a
93 short while ago (e.g. the server failed) and we've only just
94 noticed, so we should only set the retry timeout on a connect
95 failure (which doesn't call this method).
96 */
97 memcached_mark_server_for_timeout(instance);
98 }
99 }
100
101 void send_quit(Memcached *memc) {
102 for (uint32_t x = 0; x < memcached_server_count(memc); x++) {
103 memcached_instance_st *instance = memcached_instance_fetch(memc, x);
104
105 memcached_quit_server(instance, false);
106 }
107 }
108
109 void memcached_quit(memcached_st *shell) {
110 Memcached *memc = memcached2Memcached(shell);
111 memcached_return_t rc;
112 if (memcached_failed(rc = initialize_query(memc, true))) {
113 return;
114 }
115
116 send_quit(memc);
117 }