cutelyst  3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
memcached.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2017-2022 Matthias Fehring <mf@huessenbergnetz.de>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "memcached_p.h"
7 
8 #include <Cutelyst/Application>
9 #include <Cutelyst/Context>
10 #include <Cutelyst/Engine>
11 #include <utility>
12 
13 #include <QLoggingCategory>
14 #include <QStringList>
15 
16 Q_LOGGING_CATEGORY(C_MEMCACHED, "cutelyst.plugin.memcached", QtWarningMsg)
17 
18 using namespace Cutelyst;
19 
20 static thread_local Memcached *mcd = nullptr;
21 const time_t Memcached::expirationNotAdd = MEMCACHED_EXPIRATION_NOT_ADD;
22 
24  : Plugin(parent)
25  , d_ptr(new MemcachedPrivate)
26 {
27 }
28 
30 {
31 }
32 
33 void Memcached::setDefaultConfig(const QVariantMap &defaultConfig)
34 {
35  Q_D(Memcached);
36  d->defaultConfig = defaultConfig;
37 }
38 
40 {
41  Q_D(Memcached);
42 
43  const QVariantMap map = app->engine()->config(QStringLiteral("Cutelyst_Memcached_Plugin"));
44  QStringList config;
45 
46  const QStringList serverList =
47  map.value(QStringLiteral("servers"), d->defaultConfig.value(QStringLiteral("servers")))
48  .toString()
49  .split(u';');
50 
51  if (serverList.empty()) {
52  config.push_back(QStringLiteral("--SERVER=localhost"));
53  }
54 
55  for (const QString &flag : {
56  QStringLiteral("verify_key"),
57  QStringLiteral("remove_failed_servers"),
58  QStringLiteral("binary_protocol"),
59  QStringLiteral("buffer_requests"),
60  QStringLiteral("hash_with_namespace"),
61  QStringLiteral("noreply"),
62  QStringLiteral("randomize_replica_read"),
63  QStringLiteral("sort_hosts"),
64  QStringLiteral("support_cas"),
65  QStringLiteral("use_udp"),
66  QStringLiteral("tcp_nodelay"),
67  QStringLiteral("tcp_keepalive"),
68  }) {
69  if (map.value(flag, d->defaultConfig.value(flag, false)).toBool()) {
70  const QString flagStr = u"--" + flag.toUpper().replace(u'_', u'-');
71  config.push_back(flagStr);
72  }
73  }
74 
75  const bool useUDP = map.value(QStringLiteral("use_udp"),
76  d->defaultConfig.value(QStringLiteral("use_udp"), false))
77  .toBool();
78 
79  for (const QString &opt : {
80  QStringLiteral("connect_timeout"),
81  QStringLiteral("distribution"),
82  QStringLiteral("hash"),
83  QStringLiteral("number_of_replicas"),
84  QStringLiteral("namespace"),
85  QStringLiteral("retry_timeout"),
86  QStringLiteral("server_failure_limit"),
87  QStringLiteral("snd_timeout"),
88  QStringLiteral("socket_recv_size"),
89  QStringLiteral("socket_send_size"),
90  QStringLiteral("poll_timeout"),
91  QStringLiteral("io_bytes_watermark"),
92  QStringLiteral("io_key_prefetch"),
93  QStringLiteral("io_msg_watermark"),
94  QStringLiteral("rcv_timeout"),
95  }) {
96  const QString _val = map.value(opt, d->defaultConfig.value(opt)).toString();
97  if (!_val.isEmpty()) {
98  const QString optStr = u"--" + opt.toUpper().replace(u'_', u'-') + u'=' + _val;
99  config.push_back(optStr); // clazy:exclude=reserve-candidates
100  }
101  }
102 
103  const QByteArray configString = config.join(u' ').toUtf8();
104 
105  bool ok = false;
106 
107  qCInfo(C_MEMCACHED,
108  "Setting up connection to memcached servers using libmemcached %s with the following "
109  "configuration string: \"%s\"",
110  memcached_lib_version(),
111  configString.constData());
112 
113  memcached_st *new_memc = memcached(configString.constData(), configString.size());
114 
115  if (new_memc) {
116 
117  if (!serverList.empty()) {
118  for (const QString &server : serverList) {
119  const auto serverParts = QStringView(server).split(u',');
120  QString name;
121  uint port = 11211;
122  uint32_t weight = 1;
123  bool isSocket = false;
124  if (!serverParts.empty()) {
125  const auto part0 = serverParts.at(0);
126  if (!part0.isEmpty()) {
127  name = part0.toString();
128  isSocket = name.startsWith(u'/');
129  }
130  if (serverParts.size() > 1) {
131  const auto part1 = serverParts.at(1);
132  if (!part1.isEmpty()) {
133  if (isSocket) {
134  weight = part1.toUInt();
135  } else {
136  port = part1.toUInt();
137  }
138  }
139  if (!isSocket && (serverParts.size() > 2)) {
140  const auto part2 = serverParts.at(2);
141  if (!part2.isEmpty()) {
142  weight = part2.toUInt();
143  }
144  }
145  }
146  }
147  if (!name.isEmpty()) {
148  memcached_return_t rc;
149  if (isSocket) {
150  rc = memcached_server_add_unix_socket_with_weight(
151  new_memc, name.toUtf8().constData(), weight);
152  if (Q_LIKELY(memcached_success(rc))) {
153  qCInfo(C_MEMCACHED,
154  "Added memcached server on socket %s with weight %u.",
155  qPrintable(name),
156  weight);
157  } else {
158  qCWarning(
159  C_MEMCACHED,
160  "Failed to add memcached server on socket %s with weight %u: %s",
161  qPrintable(name),
162  weight,
163  memcached_strerror(new_memc, rc));
164  }
165  } else {
166  if (useUDP) {
167  rc = memcached_server_add_udp_with_weight(
168  new_memc, name.toUtf8().constData(), port, weight);
169  } else {
170  rc = memcached_server_add_with_weight(
171  new_memc, name.toUtf8().constData(), port, weight);
172  }
173  if (Q_LIKELY(memcached_success(rc))) {
174  qCInfo(C_MEMCACHED,
175  "Added memcached server on host %s:%u with weight %u.",
176  qPrintable(name),
177  port,
178  weight);
179  } else {
180  qCWarning(
181  C_MEMCACHED,
182  "Failed to add memcached server on host %s:%u with weight %u: %s",
183  qPrintable(name),
184  port,
185  weight,
186  memcached_strerror(new_memc, rc));
187  }
188  }
189  }
190  }
191 
192  if (Q_UNLIKELY(memcached_server_count(new_memc) == 0)) {
193  qCWarning(C_MEMCACHED,
194  "Failed to add any memcached server. Adding default server on localhost "
195  "port 11211.");
196  memcached_return_t rc = memcached_server_add(new_memc, "localhost", 11211);
197  if (Q_UNLIKELY(!memcached_success(rc))) {
198  qCCritical(C_MEMCACHED,
199  "Failed to add default memcached server. Memcached plugin will not "
200  "work without a configured server! %s",
201  memcached_strerror(new_memc, rc));
202  memcached_free(new_memc);
203  return false;
204  }
205  }
206  }
207 
208  d->compression = map.value(QStringLiteral("compression"),
209  d->defaultConfig.value(QStringLiteral("compression"), false))
210  .toBool();
211  d->compressionLevel =
212  map.value(QStringLiteral("compression_level"),
213  d->defaultConfig.value(QStringLiteral("compression_level"), -1))
214  .toInt();
215  d->compressionThreshold =
216  map.value(QStringLiteral("compression_threshold"),
217  d->defaultConfig.value(QStringLiteral("compression_threshold"), 100))
218  .toInt();
219  if (d->compression) {
220  qCInfo(C_MEMCACHED,
221  "Compression: enabled (Compression level: %i, Compression threshold: %i bytes)",
222  d->compressionLevel,
223  d->compressionThreshold);
224  } else {
225  qCInfo(C_MEMCACHED, "Compression: disabled");
226  }
227 
228  const QString encKey = map.value(QStringLiteral("encryption_key")).toString();
229  if (!encKey.isEmpty()) {
230  const QByteArray encKeyBa = encKey.toUtf8();
231  const memcached_return_t rt =
232  memcached_set_encoding_key(new_memc, encKeyBa.constData(), encKeyBa.size());
233  if (Q_LIKELY(memcached_success(rt))) {
234  qCInfo(C_MEMCACHED, "Encryption: enabled");
235  } else {
236  qCWarning(C_MEMCACHED,
237  "Failed to enable encryption: %s",
238  memcached_strerror(new_memc, rt));
239  }
240  } else {
241  qCInfo(C_MEMCACHED, "Encryption: disabled");
242  }
243 
244 #ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
245 # if LIBMEMCACHED_WITH_SASL_SUPPORT == 1
246  const QString saslUser = map.value(QStringLiteral("sasl_user")).toString();
247  const QString saslPass = map.value(QStringLiteral("sasl_password")).toString();
248  if (!saslUser.isEmpty() && !saslPass.isEmpty()) {
249  const memcached_return_t rt = memcached_set_sasl_auth_data(
250  new_memc, saslUser.toUtf8().constData(), saslPass.toUtf8().constData());
251  if (Q_LIKELY(memcached_success(rt))) {
252  qCInfo(C_MEMCACHED, "SASL authentication: enabled");
253  d->saslEnabled = true;
254  } else {
255  qCWarning(C_MEMCACHED,
256  "Failed to enable SASL authentication: %s",
257  memcached_strerror(new_memc, rt));
258  }
259  } else {
260  qCInfo(C_MEMCACHED, "SASL authentication: disabled");
261  }
262 # endif
263 #endif
264 
265  if (d->memc) {
266  memcached_free(d->memc);
267  }
268  d->memc = new_memc;
269  ok = true;
270  }
271 
272  if (ok) {
273  connect(app, &Application::postForked, this, [=] { mcd = this; });
274  app->loadTranslations(QStringLiteral("plugin_memcached"));
275  } else {
276  qCCritical(C_MEMCACHED) << "Failed to configure the connection to the memcached server(s)";
277  }
278 
279  return ok;
280 }
281 
282 bool Memcached::set(const QString &key,
283  const QByteArray &value,
284  time_t expiration,
286 {
287  if (!mcd) {
288  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
289  if (returnType) {
290  *returnType = Memcached::PluginNotRegisterd;
291  }
292  return false;
293  }
294 
295  const QByteArray _key = key.toUtf8();
296 
297  MemcachedPrivate::Flags flags;
298  QByteArray _value = value;
299 
300  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
301  flags |= MemcachedPrivate::Compressed;
302  _value = qCompress(value, mcd->d_ptr->compressionLevel);
303  }
304 
305  const memcached_return_t rt = memcached_set(mcd->d_ptr->memc,
306  _key.constData(),
307  _key.size(),
308  _value.constData(),
309  _value.size(),
310  expiration,
311  flags);
312 
313  const bool ok = memcached_success(rt);
314 
315  if (!ok) {
316  qCWarning(C_MEMCACHED,
317  "Failed to store key \"%s\": %s",
318  _key.constData(),
319  memcached_strerror(mcd->d_ptr->memc, rt));
320  }
321 
322  MemcachedPrivate::setReturnType(returnType, rt);
323 
324  return ok;
325 }
326 
327 bool Memcached::setByKey(const QString &groupKey,
328  const QString &key,
329  const QByteArray &value,
330  time_t expiration,
331  MemcachedReturnType *returnType)
332 {
333  if (!mcd) {
334  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
335  if (returnType) {
336  *returnType = Memcached::PluginNotRegisterd;
337  }
338  return false;
339  }
340 
341  const QByteArray _key = key.toUtf8();
342  const QByteArray _groupKey = groupKey.toUtf8();
343 
344  MemcachedPrivate::Flags flags;
345  QByteArray _value = value;
346 
347  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
348  flags |= MemcachedPrivate::Compressed;
349  _value = qCompress(value, mcd->d_ptr->compressionLevel);
350  }
351 
352  const memcached_return_t rt = memcached_set_by_key(mcd->d_ptr->memc,
353  _groupKey.constData(),
354  _groupKey.size(),
355  _key.constData(),
356  _key.size(),
357  _value.constData(),
358  _value.size(),
359  expiration,
360  flags);
361 
362  const bool ok = memcached_success(rt);
363 
364  if (!ok) {
365  qCWarning(C_MEMCACHED,
366  "Failed to store key \"%s\" on group \"%s\": %s",
367  _key.constData(),
368  _groupKey.constData(),
369  memcached_strerror(mcd->d_ptr->memc, rt));
370  }
371 
372  MemcachedPrivate::setReturnType(returnType, rt);
373 
374  return ok;
375 }
376 
377 bool Memcached::add(const QString &key,
378  const QByteArray &value,
379  time_t expiration,
380  MemcachedReturnType *returnType)
381 {
382  if (!mcd) {
383  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
384  if (returnType) {
385  *returnType = Memcached::PluginNotRegisterd;
386  }
387  return false;
388  }
389 
390  const QByteArray _key = key.toUtf8();
391 
392  MemcachedPrivate::Flags flags;
393  QByteArray _value = value;
394 
395  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
396  flags |= MemcachedPrivate::Compressed;
397  _value = qCompress(value, mcd->d_ptr->compressionLevel);
398  }
399 
400  const memcached_return_t rt = memcached_add(mcd->d_ptr->memc,
401  _key.constData(),
402  _key.size(),
403  _value.constData(),
404  _value.size(),
405  expiration,
406  flags);
407 
408  const bool ok = memcached_success(rt);
409 
410  if (!ok && (rt != MEMCACHED_NOTSTORED)) {
411  qCWarning(C_MEMCACHED,
412  "Failed to add key \"%s\": %s",
413  _key.constData(),
414  memcached_strerror(mcd->d_ptr->memc, rt));
415  }
416 
417  MemcachedPrivate::setReturnType(returnType, rt);
418 
419  return ok;
420 }
421 
422 bool Memcached::addByKey(const QString &groupKey,
423  const QString &key,
424  const QByteArray &value,
425  time_t expiration,
426  MemcachedReturnType *returnType)
427 {
428  if (!mcd) {
429  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
430  if (returnType) {
431  *returnType = Memcached::PluginNotRegisterd;
432  }
433  return false;
434  }
435 
436  const QByteArray _key = key.toUtf8();
437  const QByteArray _groupKey = groupKey.toUtf8();
438 
439  MemcachedPrivate::Flags flags;
440  QByteArray _value = value;
441 
442  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
443  flags |= MemcachedPrivate::Compressed;
444  _value = qCompress(value, mcd->d_ptr->compressionLevel);
445  }
446 
447  const memcached_return_t rt = memcached_add_by_key(mcd->d_ptr->memc,
448  _groupKey.constData(),
449  _groupKey.size(),
450  _key.constData(),
451  _key.size(),
452  _value.constData(),
453  _value.size(),
454  expiration,
455  flags);
456 
457  const bool ok = memcached_success(rt);
458 
459  if (!ok && (rt != MEMCACHED_NOTSTORED)) {
460  qCWarning(C_MEMCACHED,
461  "Failed to add key \"%s\" on group \"%s\": %s",
462  _key.constData(),
463  _groupKey.constData(),
464  memcached_strerror(mcd->d_ptr->memc, rt));
465  }
466 
467  MemcachedPrivate::setReturnType(returnType, rt);
468 
469  return ok;
470 }
471 
472 bool Memcached::replace(const QString &key,
473  const QByteArray &value,
474  time_t expiration,
475  MemcachedReturnType *returnType)
476 {
477  if (!mcd) {
478  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
479  if (returnType) {
480  *returnType = Memcached::PluginNotRegisterd;
481  }
482  return false;
483  }
484 
485  const QByteArray _key = key.toUtf8();
486 
487  MemcachedPrivate::Flags flags;
488  QByteArray _value = value;
489 
490  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
491  flags |= MemcachedPrivate::Compressed;
492  _value = qCompress(value, mcd->d_ptr->compressionLevel);
493  }
494 
495  const memcached_return_t rt = memcached_replace(mcd->d_ptr->memc,
496  _key.constData(),
497  _key.size(),
498  _value.constData(),
499  _value.size(),
500  expiration,
501  flags);
502 
503  const bool ok = memcached_success(rt);
504 
505  if (!ok && (rt != MEMCACHED_NOTSTORED)) {
506  qCWarning(C_MEMCACHED,
507  "Failed to replace key \"%s\": %s",
508  _key.constData(),
509  memcached_strerror(mcd->d_ptr->memc, rt));
510  }
511 
512  MemcachedPrivate::setReturnType(returnType, rt);
513 
514  return ok;
515 }
516 
517 bool Memcached::replaceByKey(const QString &groupKey,
518  const QString &key,
519  const QByteArray &value,
520  time_t expiration,
521  MemcachedReturnType *returnType)
522 {
523  if (!mcd) {
524  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
525  if (returnType) {
526  *returnType = Memcached::PluginNotRegisterd;
527  }
528  return false;
529  }
530 
531  const QByteArray _groupKey = groupKey.toUtf8();
532  const QByteArray _key = key.toUtf8();
533 
534  MemcachedPrivate::Flags flags;
535  QByteArray _value = value;
536 
537  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
538  flags |= MemcachedPrivate::Compressed;
539  _value = qCompress(value, mcd->d_ptr->compressionLevel);
540  }
541 
542  const memcached_return_t rt = memcached_replace_by_key(mcd->d_ptr->memc,
543  _groupKey.constData(),
544  _groupKey.size(),
545  _key.constData(),
546  _key.size(),
547  _value.constData(),
548  _value.size(),
549  expiration,
550  flags);
551 
552  const bool ok = memcached_success(rt);
553 
554  if (!ok && (rt != MEMCACHED_NOTSTORED)) {
555  qCWarning(C_MEMCACHED,
556  "Failed to replace key \"%s\" on group \"%s\": %s",
557  _key.constData(),
558  _groupKey.constData(),
559  memcached_strerror(mcd->d_ptr->memc, rt));
560  }
561 
562  MemcachedPrivate::setReturnType(returnType, rt);
563 
564  return ok;
565 }
566 
568  uint64_t *cas,
570 {
571  QByteArray retData;
572 
573  if (!mcd) {
574  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
575  if (returnType) {
576  *returnType = Memcached::PluginNotRegisterd;
577  }
578  return retData;
579  }
580 
581  memcached_return_t rt;
582  const QByteArray _key = key.toUtf8();
583  bool ok = false;
584 
585  std::vector<const char *> keys;
586  std::vector<size_t> sizes;
587  keys.push_back(_key.constData());
588  sizes.push_back(_key.size());
589  rt = memcached_mget(mcd->d_ptr->memc, &keys[0], &sizes[0], keys.size());
590 
591  if (memcached_success(rt)) {
592  memcached_result_st *result = memcached_fetch_result(mcd->d_ptr->memc, NULL, &rt);
593  if (result) {
594  retData = QByteArray(memcached_result_value(result), memcached_result_length(result));
595  if (cas) {
596  *cas = memcached_result_cas(result);
597  }
598  MemcachedPrivate::Flags flags = MemcachedPrivate::Flags(memcached_result_flags(result));
599  if (flags.testFlag(MemcachedPrivate::Compressed)) {
600  retData = qUncompress(retData);
601  }
602  ok = true;
603  // fetch another result even if there is no one to get
604  // a NULL for the internal of libmemcached
605  memcached_fetch_result(mcd->d_ptr->memc, NULL, NULL);
606  }
607  memcached_result_free(result);
608  }
609 
610  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
611  qCWarning(C_MEMCACHED,
612  "Failed to get data for key \"%s\": %s",
613  _key.constData(),
614  memcached_strerror(mcd->d_ptr->memc, rt));
615  }
616 
617  MemcachedPrivate::setReturnType(returnType, rt);
618 
619  return retData;
620 }
621 
623  const QString &key,
624  uint64_t *cas,
625  MemcachedReturnType *returnType)
626 {
627  QByteArray retData;
628 
629  if (!mcd) {
630  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
631  if (returnType) {
632  *returnType = Memcached::PluginNotRegisterd;
633  }
634  return retData;
635  }
636 
637  memcached_return_t rt;
638  const QByteArray _groupKey = groupKey.toUtf8();
639  const QByteArray _key = key.toUtf8();
640  bool ok = false;
641 
642  std::vector<const char *> keys;
643  std::vector<size_t> sizes;
644  keys.push_back(_key.constData());
645  sizes.push_back(_key.size());
646  rt = memcached_mget_by_key(mcd->d_ptr->memc,
647  _groupKey.constData(),
648  _groupKey.size(),
649  &keys[0],
650  &sizes[0],
651  keys.size());
652 
653  if (memcached_success(rt)) {
654  memcached_result_st *result = memcached_fetch_result(mcd->d_ptr->memc, NULL, &rt);
655  if (result) {
656  retData = QByteArray(memcached_result_value(result), memcached_result_length(result));
657  if (cas) {
658  *cas = memcached_result_cas(result);
659  }
660  MemcachedPrivate::Flags flags = MemcachedPrivate::Flags(memcached_result_flags(result));
661  if (flags.testFlag(MemcachedPrivate::Compressed)) {
662  retData = qUncompress(retData);
663  }
664  ok = true;
665  // fetch another result even if there is no one to get
666  // a NULL for the internal of libmemcached
667  memcached_fetch_result(mcd->d_ptr->memc, NULL, NULL);
668  }
669  memcached_result_free(result);
670  }
671 
672  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
673  qCWarning(C_MEMCACHED,
674  "Failed to get data for key \"%s\" on group \"%s\": %s",
675  _key.constData(),
676  _groupKey.constData(),
677  memcached_strerror(mcd->d_ptr->memc, rt));
678  }
679 
680  MemcachedPrivate::setReturnType(returnType, rt);
681 
682  return retData;
683 }
684 
685 bool Memcached::remove(const QString &key, MemcachedReturnType *returnType)
686 {
687  if (!mcd) {
688  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
689  if (returnType) {
690  *returnType = Memcached::PluginNotRegisterd;
691  }
692  return false;
693  }
694 
695  const QByteArray _key = key.toUtf8();
696 
697  const memcached_return_t rt =
698  memcached_delete(mcd->d_ptr->memc, _key.constData(), _key.size(), 0);
699 
700  const bool ok = memcached_success(rt);
701 
702  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
703  qCWarning(C_MEMCACHED,
704  "Failed to remove data for key \"%s\": %s",
705  _key.constData(),
706  memcached_strerror(mcd->d_ptr->memc, rt));
707  }
708 
709  MemcachedPrivate::setReturnType(returnType, rt);
710 
711  return ok;
712 }
713 
714 bool Memcached::removeByKey(const QString &groupKey,
715  const QString &key,
716  MemcachedReturnType *returnType)
717 {
718  if (!mcd) {
719  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
720  if (returnType) {
721  *returnType = Memcached::PluginNotRegisterd;
722  }
723  return false;
724  }
725 
726  const QByteArray _groupKey = groupKey.toUtf8();
727  const QByteArray _key = key.toUtf8();
728 
729  const memcached_return_t rt = memcached_delete_by_key(mcd->d_ptr->memc,
730  _groupKey.constData(),
731  _groupKey.size(),
732  _key.constData(),
733  _key.size(),
734  0);
735 
736  const bool ok = memcached_success(rt);
737 
738  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
739  qCWarning(C_MEMCACHED,
740  "Failed to remove data for key \"%s\" on group \"%s\": %s",
741  _key.constData(),
742  _groupKey.constData(),
743  memcached_strerror(mcd->d_ptr->memc, rt));
744  }
745 
746  MemcachedPrivate::setReturnType(returnType, rt);
747 
748  return ok;
749 }
750 
751 bool Memcached::exist(const QString &key, MemcachedReturnType *returnType)
752 {
753  if (!mcd) {
754  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
755  if (returnType) {
756  *returnType = Memcached::PluginNotRegisterd;
757  }
758  return false;
759  }
760 
761  const QByteArray _key = key.toUtf8();
762 
763  const memcached_return_t rt = memcached_exist(mcd->d_ptr->memc, _key.constData(), _key.size());
764 
765  const bool ok = memcached_success(rt);
766 
767  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
768  qCWarning(C_MEMCACHED,
769  "Failed to check existence of key \"%s\": %s",
770  _key.constData(),
771  memcached_strerror(mcd->d_ptr->memc, rt));
772  }
773 
774  MemcachedPrivate::setReturnType(returnType, rt);
775 
776  return ok;
777 }
778 
779 bool Memcached::existByKey(const QString &groupKey,
780  const QString &key,
781  MemcachedReturnType *returnType)
782 {
783  if (!mcd) {
784  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
785  if (returnType) {
786  *returnType = Memcached::PluginNotRegisterd;
787  }
788  return false;
789  }
790 
791  const QByteArray _groupKey = groupKey.toUtf8();
792  const QByteArray _key = key.toUtf8();
793 
794  const memcached_return_t rt = memcached_exist_by_key(
795  mcd->d_ptr->memc, _groupKey.constData(), _groupKey.size(), _key.constData(), _key.size());
796 
797  const bool ok = memcached_success(rt);
798 
799  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
800  qCWarning(C_MEMCACHED,
801  "Failed to check existence of key \"%s\" in group \"%s\"",
802  _key.constData(),
803  _groupKey.constData());
804  }
805 
806  MemcachedPrivate::setReturnType(returnType, rt);
807 
808  return ok;
809 }
810 
812  uint32_t offset,
813  uint64_t *value,
814  MemcachedReturnType *returnType)
815 {
816  if (!mcd) {
817  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
818  if (returnType) {
819  *returnType = Memcached::PluginNotRegisterd;
820  }
821  return false;
822  }
823 
824  const QByteArray _key = key.toUtf8();
825 
826  const memcached_return_t rt =
827  memcached_increment(mcd->d_ptr->memc, _key.constData(), _key.size(), offset, value);
828 
829  const bool ok = memcached_success(rt);
830 
831  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
832  qCWarning(C_MEMCACHED,
833  "Failed to increment key \"%s\" by %u: %s",
834  _key.constData(),
835  offset,
836  memcached_strerror(mcd->d_ptr->memc, rt));
837  }
838 
839  MemcachedPrivate::setReturnType(returnType, rt);
840 
841  return ok;
842 }
843 
844 bool Memcached::incrementByKey(const QString &groupKey,
845  const QString &key,
846  uint64_t offset,
847  uint64_t *value,
848  MemcachedReturnType *returnType)
849 {
850  if (!mcd) {
851  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
852  if (returnType) {
853  *returnType = Memcached::PluginNotRegisterd;
854  }
855  return false;
856  }
857 
858  const QByteArray _group = groupKey.toUtf8();
859  const QByteArray _key = key.toUtf8();
860 
861  const memcached_return_t rt = memcached_increment_by_key(mcd->d_ptr->memc,
862  _group.constData(),
863  _group.size(),
864  _key.constData(),
865  _key.size(),
866  offset,
867  value);
868 
869  const bool ok = memcached_success(rt);
870 
871  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
872  qCWarning(C_MEMCACHED,
873  "Failed to increment \"%s\" key on group \"%s\" by %lu: %s",
874  _key.constData(),
875  _group.constData(),
876  offset,
877  memcached_strerror(mcd->d_ptr->memc, rt));
878  }
879 
880  MemcachedPrivate::setReturnType(returnType, rt);
881 
882  return ok;
883 }
884 
886  uint64_t offset,
887  uint64_t initial,
888  time_t expiration,
889  uint64_t *value,
890  MemcachedReturnType *returnType)
891 {
892  if (!mcd) {
893  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
894  if (returnType) {
895  *returnType = Memcached::PluginNotRegisterd;
896  }
897  return false;
898  }
899 
900  const QByteArray _key = key.toUtf8();
901 
902  const memcached_return_t rt = memcached_increment_with_initial(
903  mcd->d_ptr->memc, _key.constData(), _key.size(), offset, initial, expiration, value);
904 
905  const bool ok = memcached_success(rt);
906 
907  if (!ok) {
908  qCWarning(C_MEMCACHED,
909  "Failed to increment or initialize key \"%s\" by offset %lu or initial %lu: %s",
910  _key.constData(),
911  offset,
912  initial,
913  memcached_strerror(mcd->d_ptr->memc, rt));
914  }
915 
916  MemcachedPrivate::setReturnType(returnType, rt);
917 
918  return ok;
919 }
920 
922  const QString &key,
923  uint64_t offset,
924  uint64_t initial,
925  time_t expiration,
926  uint64_t *value,
927  MemcachedReturnType *returnType)
928 {
929  if (!mcd) {
930  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
931  if (returnType) {
932  *returnType = Memcached::PluginNotRegisterd;
933  }
934  return false;
935  }
936 
937  const QByteArray _group = groupKey.toUtf8();
938  const QByteArray _key = key.toUtf8();
939 
940  const memcached_return_t rt = memcached_increment_with_initial_by_key(mcd->d_ptr->memc,
941  _group.constData(),
942  _group.size(),
943  _key.constData(),
944  _key.size(),
945  offset,
946  initial,
947  expiration,
948  value);
949 
950  const bool ok = memcached_success(rt);
951  if (!ok) {
952  qCWarning(C_MEMCACHED,
953  "Failed to increment or initialize key \"%s\" in group \"%s\" by offset %lu or "
954  "initial %lu: %s",
955  _key.constData(),
956  _group.constData(),
957  offset,
958  initial,
959  memcached_strerror(mcd->d_ptr->memc, rt));
960  }
961 
962  MemcachedPrivate::setReturnType(returnType, rt);
963 
964  return ok;
965 }
966 
968  uint32_t offset,
969  uint64_t *value,
970  MemcachedReturnType *returnType)
971 {
972  if (!mcd) {
973  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
974  if (returnType) {
975  *returnType = Memcached::PluginNotRegisterd;
976  }
977  return false;
978  }
979 
980  const QByteArray _key = key.toUtf8();
981 
982  const memcached_return_t rt =
983  memcached_decrement(mcd->d_ptr->memc, _key.constData(), _key.size(), offset, value);
984 
985  const bool ok = memcached_success(rt);
986 
987  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
988  qCWarning(C_MEMCACHED,
989  "Failed to decrement key \"%s\" by %u: %s",
990  _key.constData(),
991  offset,
992  memcached_strerror(mcd->d_ptr->memc, rt));
993  }
994 
995  MemcachedPrivate::setReturnType(returnType, rt);
996 
997  return ok;
998 }
999 
1000 bool Memcached::decrementByKey(const QString &groupKey,
1001  const QString &key,
1002  uint64_t offset,
1003  uint64_t *value,
1004  MemcachedReturnType *returnType)
1005 {
1006  if (!mcd) {
1007  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1008  if (returnType) {
1009  *returnType = Memcached::PluginNotRegisterd;
1010  }
1011  return false;
1012  }
1013 
1014  const QByteArray _group = groupKey.toUtf8();
1015  const QByteArray _key = key.toUtf8();
1016 
1017  const memcached_return_t rt = memcached_decrement_by_key(mcd->d_ptr->memc,
1018  _group.constData(),
1019  _group.size(),
1020  _key.constData(),
1021  _key.size(),
1022  offset,
1023  value);
1024 
1025  const bool ok = memcached_success(rt);
1026 
1027  if (!ok && (rt != MEMCACHED_NOTFOUND)) {
1028  qCWarning(C_MEMCACHED,
1029  "Failed to decrement \"%s\" key on group \"%s\" by %lu: %s",
1030  _key.constData(),
1031  _group.constData(),
1032  offset,
1033  memcached_strerror(mcd->d_ptr->memc, rt));
1034  }
1035 
1036  MemcachedPrivate::setReturnType(returnType, rt);
1037 
1038  return ok;
1039 }
1040 
1042  uint64_t offset,
1043  uint64_t initial,
1044  time_t expiration,
1045  uint64_t *value,
1046  MemcachedReturnType *returnType)
1047 {
1048  if (!mcd) {
1049  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1050  if (returnType) {
1051  *returnType = Memcached::PluginNotRegisterd;
1052  }
1053  return false;
1054  }
1055 
1056  const QByteArray _key = key.toUtf8();
1057 
1058  const memcached_return_t rt = memcached_decrement_with_initial(
1059  mcd->d_ptr->memc, _key.constData(), _key.size(), offset, initial, expiration, value);
1060 
1061  const bool ok = memcached_success(rt);
1062 
1063  if (!ok) {
1064  qCWarning(C_MEMCACHED,
1065  "Failed to decrement or initialize key \"%s\" by offset %lu or initial %lu: %s",
1066  _key.constData(),
1067  offset,
1068  initial,
1069  memcached_strerror(mcd->d_ptr->memc, rt));
1070  }
1071 
1072  MemcachedPrivate::setReturnType(returnType, rt);
1073 
1074  return ok;
1075 }
1076 
1078  const QString &key,
1079  uint64_t offset,
1080  uint64_t initial,
1081  time_t expiration,
1082  uint64_t *value,
1083  MemcachedReturnType *returnType)
1084 {
1085  if (!mcd) {
1086  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1087  if (returnType) {
1088  *returnType = Memcached::PluginNotRegisterd;
1089  }
1090  return false;
1091  }
1092 
1093  const QByteArray _group = groupKey.toUtf8();
1094  const QByteArray _key = key.toUtf8();
1095 
1096  const memcached_return_t rt = memcached_decrement_with_initial_by_key(mcd->d_ptr->memc,
1097  _group.constData(),
1098  _group.size(),
1099  _key.constData(),
1100  _key.size(),
1101  offset,
1102  initial,
1103  expiration,
1104  value);
1105 
1106  const bool ok = memcached_success(rt);
1107  if (!ok) {
1108  qCWarning(C_MEMCACHED,
1109  "Failed to increment or initialize key \"%s\" in group \"%s\" by offset %lu or "
1110  "initial %lu: %s",
1111  _key.constData(),
1112  _group.constData(),
1113  offset,
1114  initial,
1115  memcached_strerror(mcd->d_ptr->memc, rt));
1116  }
1117 
1118  MemcachedPrivate::setReturnType(returnType, rt);
1119 
1120  return ok;
1121 }
1122 
1123 bool Memcached::cas(const QString &key,
1124  const QByteArray &value,
1125  time_t expiration,
1126  uint64_t cas,
1127  MemcachedReturnType *returnType)
1128 {
1129  if (!mcd) {
1130  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1131  if (returnType) {
1132  *returnType = Memcached::PluginNotRegisterd;
1133  }
1134  return false;
1135  }
1136 
1137  const QByteArray _key = key.toUtf8();
1138 
1139  MemcachedPrivate::Flags flags;
1140  QByteArray _value = value;
1141 
1142  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
1143  flags |= MemcachedPrivate::Compressed;
1144  _value = qCompress(value, mcd->d_ptr->compressionLevel);
1145  }
1146 
1147  const memcached_return_t rt = memcached_cas(mcd->d_ptr->memc,
1148  _key.constData(),
1149  _key.size(),
1150  _value.constData(),
1151  _value.size(),
1152  expiration,
1153  flags,
1154  cas);
1155 
1156  const bool ok = memcached_success(rt);
1157 
1158  if (!ok && (rt != MEMCACHED_DATA_EXISTS)) {
1159  qCWarning(C_MEMCACHED,
1160  "Failed to compare and set (cas) key \"%s\": %s",
1161  _key.constData(),
1162  memcached_strerror(mcd->d_ptr->memc, rt));
1163  }
1164 
1165  MemcachedPrivate::setReturnType(returnType, rt);
1166 
1167  return ok;
1168 }
1169 
1170 bool Memcached::casByKey(const QString &groupKey,
1171  const QString &key,
1172  const QByteArray &value,
1173  time_t expiration,
1174  uint64_t cas,
1175  MemcachedReturnType *returnType)
1176 {
1177  if (!mcd) {
1178  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1179  if (returnType) {
1180  *returnType = Memcached::PluginNotRegisterd;
1181  }
1182  return false;
1183  }
1184 
1185  const QByteArray _group = groupKey.toUtf8();
1186  const QByteArray _key = key.toUtf8();
1187 
1188  MemcachedPrivate::Flags flags;
1189  QByteArray _value = value;
1190 
1191  if (mcd->d_ptr->compression && (_value.size() > mcd->d_ptr->compressionThreshold)) {
1192  flags |= MemcachedPrivate::Compressed;
1193  _value = qCompress(value, mcd->d_ptr->compressionLevel);
1194  }
1195 
1196  const memcached_return_t rt = memcached_cas_by_key(mcd->d_ptr->memc,
1197  _group.constData(),
1198  _group.size(),
1199  _key.constData(),
1200  _key.size(),
1201  _value.constData(),
1202  _value.size(),
1203  expiration,
1204  flags,
1205  cas);
1206 
1207  const bool ok = memcached_success(rt);
1208 
1209  if (!ok && (rt != MEMCACHED_DATA_EXISTS)) {
1210  qCWarning(C_MEMCACHED,
1211  "Failed to compare and set (cas) key \"%s\" in group \"%s\": %s",
1212  _key.constData(),
1213  _group.constData(),
1214  memcached_strerror(mcd->d_ptr->memc, rt));
1215  }
1216 
1217  MemcachedPrivate::setReturnType(returnType, rt);
1218 
1219  return ok;
1220 }
1221 
1223 {
1224  if (!mcd) {
1225  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1226  if (returnType) {
1227  *returnType = Memcached::PluginNotRegisterd;
1228  }
1229  return false;
1230  }
1231 
1232  const memcached_return_t rt = memcached_flush_buffers(mcd->d_ptr->memc);
1233 
1234  const bool ok = memcached_success(rt);
1235 
1236  if (!ok) {
1237  qCWarning(
1238  C_MEMCACHED, "Failed to flush buffers: %s", memcached_strerror(mcd->d_ptr->memc, rt));
1239  }
1240 
1241  MemcachedPrivate::setReturnType(returnType, rt);
1242 
1243  return ok;
1244 }
1245 
1246 bool Memcached::flush(time_t expiration, MemcachedReturnType *returnType)
1247 {
1248  if (!mcd) {
1249  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1250  if (returnType) {
1251  *returnType = Memcached::PluginNotRegisterd;
1252  }
1253  return false;
1254  }
1255 
1256  const memcached_return_t rt = memcached_flush(mcd->d_ptr->memc, expiration);
1257 
1258  const bool ok = memcached_success(rt);
1259 
1260  if (!ok) {
1261  qCWarning(C_MEMCACHED,
1262  "Failed to wipe clean (flush) server content: %s",
1263  memcached_strerror(mcd->d_ptr->memc, rt));
1264  }
1265 
1266  MemcachedPrivate::setReturnType(returnType, rt);
1267 
1268  return ok;
1269 }
1270 
1272  QHash<QString, uint64_t> *casValues,
1273  MemcachedReturnType *returnType)
1274 {
1276 
1277  if (!mcd) {
1278  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1279  if (returnType) {
1280  *returnType = Memcached::PluginNotRegisterd;
1281  }
1282  return ret;
1283  }
1284 
1285  if (keys.empty()) {
1286  qCWarning(C_MEMCACHED, "Can not get multiple values without a list of keys.");
1287  if (returnType) {
1288  *returnType = Memcached::BadKeyProvided;
1289  }
1290  return ret;
1291  }
1292 
1293  std::vector<char *> _keys;
1294  _keys.reserve(keys.size());
1295  std::vector<size_t> _keysSizes;
1296  _keysSizes.reserve(keys.size());
1297 
1298  for (const QString &key : keys) {
1299  const QByteArray _key = key.toUtf8();
1300  char *data = new char[_key.size() + 1];
1301  qstrcpy(data, _key.data());
1302  _keys.push_back(data);
1303  _keysSizes.push_back(_key.size());
1304  }
1305 
1306  memcached_return_t rt;
1307  bool ok = false;
1308 
1309  rt = memcached_mget(mcd->d_ptr->memc, &_keys[0], &_keysSizes[0], _keys.size());
1310 
1311  if (memcached_success(rt)) {
1312  ok = true;
1313  ret.reserve(keys.size());
1314  while ((rt != MEMCACHED_END) && (rt != MEMCACHED_NOTFOUND)) {
1315  memcached_result_st *result = memcached_fetch_result(mcd->d_ptr->memc, NULL, &rt);
1316  if (result) {
1317  const QString rk = QString::fromUtf8(memcached_result_key_value(result),
1318  memcached_result_key_length(result));
1319  QByteArray rd(memcached_result_value(result), memcached_result_length(result));
1320  if (casValues) {
1321  casValues->insert(rk, memcached_result_cas(result));
1322  }
1323  MemcachedPrivate::Flags flags =
1324  MemcachedPrivate::Flags(memcached_result_flags(result));
1325  if (flags.testFlag(MemcachedPrivate::Compressed)) {
1326  rd = qUncompress(rd);
1327  }
1328  ret.insert(rk, rd);
1329  }
1330  memcached_result_free(result);
1331  }
1332  }
1333 
1334  for (char *c : _keys) {
1335  delete[] c;
1336  }
1337 
1338  if (!ok) {
1339  qCWarning(C_MEMCACHED,
1340  "Failed to get values for multiple keys: %s",
1341  memcached_strerror(mcd->d_ptr->memc, rt));
1342  }
1343 
1344  MemcachedPrivate::setReturnType(returnType, rt);
1345 
1346  return ret;
1347 }
1348 
1350  const QStringList &keys,
1351  QHash<QString, uint64_t> *casValues,
1352  MemcachedReturnType *returnType)
1353 {
1355 
1356  if (!mcd) {
1357  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1358  if (returnType) {
1359  *returnType = Memcached::PluginNotRegisterd;
1360  }
1361  return ret;
1362  }
1363 
1364  if (groupKey.isEmpty()) {
1365  qCWarning(C_MEMCACHED,
1366  "Can not get multiple values from specific server when groupKey is empty.");
1367  if (returnType) {
1368  *returnType = Memcached::BadKeyProvided;
1369  }
1370  return ret;
1371  }
1372 
1373  if (keys.empty()) {
1374  qCWarning(C_MEMCACHED, "Can not get multiple values without a list of keys.");
1375  if (returnType) {
1376  *returnType = Memcached::BadKeyProvided;
1377  }
1378  return ret;
1379  }
1380 
1381  const QByteArray _group = groupKey.toUtf8();
1382 
1383  std::vector<char *> _keys;
1384  _keys.reserve(keys.size());
1385  std::vector<size_t> _keysSizes;
1386  _keysSizes.reserve(keys.size());
1387 
1388  for (const QString &key : keys) {
1389  const QByteArray _key = key.toUtf8();
1390  char *data = new char[_key.size() + 1];
1391  strcpy(data, _key.data());
1392  _keys.push_back(data);
1393  _keysSizes.push_back(_key.size());
1394  }
1395 
1396  memcached_return_t rt;
1397  bool ok = false;
1398 
1399  rt = memcached_mget_by_key(mcd->d_ptr->memc,
1400  _group.constData(),
1401  _group.size(),
1402  &_keys[0],
1403  &_keysSizes[0],
1404  _keys.size());
1405 
1406  if (memcached_success(rt)) {
1407  ok = true;
1408  ret.reserve(keys.size());
1409  while ((rt != MEMCACHED_END) && (rt != MEMCACHED_NOTFOUND)) {
1410  memcached_result_st *result = memcached_fetch_result(mcd->d_ptr->memc, NULL, &rt);
1411  if (result) {
1412  const QString rk = QString::fromUtf8(memcached_result_key_value(result),
1413  memcached_result_key_length(result));
1414  QByteArray rd(memcached_result_value(result), memcached_result_length(result));
1415  if (casValues) {
1416  casValues->insert(rk, memcached_result_cas(result));
1417  }
1418  MemcachedPrivate::Flags flags =
1419  MemcachedPrivate::Flags(memcached_result_flags(result));
1420  if (flags.testFlag(MemcachedPrivate::Compressed)) {
1421  rd = qUncompress(rd);
1422  }
1423  ret.insert(rk, rd);
1424  }
1425  memcached_result_free(result);
1426  }
1427  }
1428 
1429  for (char *c : _keys) {
1430  delete[] c;
1431  }
1432 
1433  if (!ok) {
1434  qCWarning(C_MEMCACHED,
1435  "Failed to get values for multiple keys in group \"%s\": %s",
1436  _group.constData(),
1437  memcached_strerror(mcd->d_ptr->memc, rt));
1438  }
1439 
1440  MemcachedPrivate::setReturnType(returnType, rt);
1441 
1442  return ret;
1443 }
1444 
1445 bool Memcached::touch(const QString &key, time_t expiration, MemcachedReturnType *returnType)
1446 {
1447  if (!mcd) {
1448  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1449  if (returnType) {
1450  *returnType = Memcached::PluginNotRegisterd;
1451  }
1452  return false;
1453  }
1454 
1455  const QByteArray _key = key.toUtf8();
1456 
1457  const memcached_return_t rt =
1458  memcached_touch(mcd->d_ptr->memc, _key.constData(), _key.size(), expiration);
1459 
1460  const bool ok = memcached_success(rt);
1461 
1462  if (!ok) {
1463  qCWarning(C_MEMCACHED,
1464  "Failed to touch key \"%s\" with new expiration time %lu: %s",
1465  _key.constData(),
1466  expiration,
1467  memcached_strerror(mcd->d_ptr->memc, rt));
1468  }
1469 
1470  MemcachedPrivate::setReturnType(returnType, rt);
1471 
1472  return ok;
1473 }
1474 
1475 bool Memcached::touchByKey(const QString &groupKey,
1476  const QString &key,
1477  time_t expiration,
1478  MemcachedReturnType *returnType)
1479 {
1480  if (!mcd) {
1481  qCCritical(C_MEMCACHED) << "Memcached plugin not registered";
1482  if (returnType) {
1483  *returnType = Memcached::PluginNotRegisterd;
1484  }
1485  return false;
1486  }
1487 
1488  const QByteArray _group = groupKey.toUtf8();
1489  const QByteArray _key = key.toUtf8();
1490 
1491  const memcached_return_t rt = memcached_touch_by_key(mcd->d_ptr->memc,
1492  _group.constData(),
1493  _group.size(),
1494  _key.constData(),
1495  _key.size(),
1496  expiration);
1497 
1498  const bool ok = memcached_success(rt);
1499 
1500  if (!ok) {
1501  qCWarning(C_MEMCACHED,
1502  "Failed to touch key \"%s\" in group \"%s\" with new expiration time %lu: %s",
1503  _key.constData(),
1504  _group.constData(),
1505  expiration,
1506  memcached_strerror(mcd->d_ptr->memc, rt));
1507  }
1508 
1509  MemcachedPrivate::setReturnType(returnType, rt);
1510 
1511  return ok;
1512 }
1513 
1515 {
1516  switch (rt) {
1517  case Memcached::Success:
1518  return c->translate("Cutelyst::Memcached", "The request was successfully executed.");
1519  case Memcached::Failure:
1520  return c->translate("Cutelyst::Memcached",
1521  "An unknown failure has occurred in the Memcached server.");
1523  return c->translate("Cutelyst::Memcached", "A DNS failure has occurred.");
1525  return c->translate(
1526  "Cutelyst::Memcached",
1527  "An unknown error has occurred while trying to connect to a Memcached server.");
1529  return c->translate("Cutelyst::Memcached",
1530  "An error has occurred while trying to write to a Memcached server.");
1532  return c->translate("Cutelyst::Memcached",
1533  "An error has occurred while trying to read from a Memcached server.");
1535  return c->translate(
1536  "Cutelyst::Memcached",
1537  "An unknown error has occurred while trying to read from a Memcached server. This only "
1538  "occures when either there is a bug in the server, or in rare cases where an ethernet "
1539  "NIC is reporting dubious information.");
1541  return c->translate("Cutelyst::Memcached",
1542  "An unknown error has occurred in the Memcached protocol.");
1544  return c->translate("Cutelyst::Memcached",
1545  "An unknown Memcached client error has occurred internally.");
1547  return c->translate("Cutelyst::Memcached",
1548  "An unknown error has occurred in the Memcached server.");
1549  case Memcached::Error:
1550  return c->translate("Cutelyst::Memcached", "A general error occurred.");
1551  case Memcached::DataExists:
1552  return c->translate("Cutelyst::Memcached", "The data for the given key alrey exists.");
1554  return c->translate("Cutelyst::Memcached",
1555  "The data requested with the key given was not found.");
1556  case Memcached::NotStored:
1557  return c->translate("Cutelyst::Memcached", "The request to store an object failed.");
1558  case Memcached::Stored:
1559  return c->translate("Cutelyst::Memcached",
1560  "The requested object has been successfully stored on the server.");
1561  case Memcached::NotFound:
1562  return c->translate("Cutelyst::Memcached", "The object requested was not found.");
1564  return c->translate("Cutelyst::Memcached",
1565  "An error has occurred while trying to allocate memory.");
1567  return c->translate("Cutelyst::Memcached",
1568  "The read operation was only partcially successful.");
1569  case Memcached::SomeErrors:
1570  return c->translate("Cutelyst::Memcached",
1571  "A multi request has been made, and some underterminate number of "
1572  "errors have occurred.");
1573  case Memcached::NoServers:
1574  return c->translate("Cutelyst::Memcached",
1575  "No servers have been added to the Memcached plugin.");
1576  case Memcached::End:
1577  return c->translate(
1578  "Cutelyst::Memcached",
1579  "The Memcached server has completed returning all of the objects requested.");
1580  case Memcached::Deleted:
1581  return c->translate("Cutelyst::Memcached",
1582  "The object requested by the key has been deleted.");
1583  case Memcached::Stat:
1584  return c->translate("Cutelyst::Memcached",
1585  "A “stat” command has been returned in the protocol.");
1586  case Memcached::Errno:
1587  return c->translate("Cutelyst::Memcached",
1588  "An error has occurred in the driver which has set errno.");
1590  return c->translate("Cutelyst::Memcached",
1591  "The given method is not supported in the Memcached server.");
1593  return c->translate("Cutelyst::Memcached",
1594  "A request has been made, but the Memcached server has not finished "
1595  "the fetch of the last request.");
1596  case Memcached::Timeout:
1597  return c->translate("Cutelyst::Memcached", "The operation has timed out.");
1598  case Memcached::Buffered:
1599  return c->translate("Cutelyst::Memcached", "The request has been buffered.");
1601  return c->translate("Cutelyst::Memcached", "The key provided is not a valid key.");
1603  return c->translate(
1604  "Cutelyst::Memcached",
1605  "The Memcached server you are connecting to has an invalid protocol. Most likely you "
1606  "are connecting to an older server that does not speak the binary protocol.");
1608  return c->translate("Cutelyst::Memcached",
1609  "The requested Memcached server has been marked dead.");
1611  return c->translate("Cutelyst::Memcached",
1612  "The Memcached server you are communicating with has a stat key which "
1613  "has not be defined in the protocol.");
1614  case Memcached::E2Big:
1615  return c->translate("Cutelyst::Memcached",
1616  "Item is too large for the Memcached server to store.");
1618  return c->translate("Cutelyst::Memcached",
1619  "The arguments supplied to the given function were not valid.");
1620  case Memcached::KeyTooBig:
1621  return c->translate(
1622  "Cutelyst::Memcached",
1623  "The key that has been provided is too large for the given Memcached server.");
1625  return c->translate("Cutelyst::Memcached",
1626  "An unknown issue has occurred during SASL authentication.");
1628  return c->translate("Cutelyst::Memcached",
1629  "The credentials provided are not valid for this Memcached server.");
1631  return c->translate("Cutelyst::Memcached", "Authentication has been paused.");
1632  case Memcached::ParseError:
1633  return c->translate(
1634  "Cutelyst::Memcached",
1635  "An error has occurred while trying to parse the configuration string.");
1637  return c->translate("Cutelyst::Memcached",
1638  "An error has occurred in parsing the configuration string.");
1639  case Memcached::Deprecated:
1640  return c->translate("Cutelyst::Memcached",
1641  "The method that was requested has been deprecated.");
1643  return c->translate(
1644  "Cutelyst::Memcached",
1645  "The Cutelyst Memcached plugin has not been registered to the application.");
1646  default:
1647  return c->translate("Cutelyst::Memcached", "An unknown error has occurred.");
1648  }
1649 }
1650 
1652 {
1653  return QVersionNumber::fromString(QLatin1String(memcached_lib_version()));
1654 }
1655 
1656 // clang-format off
1657 Memcached::MemcachedReturnType MemcachedPrivate::returnTypeConvert(memcached_return_t rt)
1658 {
1659  switch (rt) {
1660  case MEMCACHED_SUCCESS: return Memcached::Success;
1661  case MEMCACHED_FAILURE: return Memcached::Failure;
1662  case MEMCACHED_HOST_LOOKUP_FAILURE: return Memcached::HostLookupFailure;
1663  case MEMCACHED_CONNECTION_FAILURE: return Memcached::ConnectionFailure;
1664  case MEMCACHED_CONNECTION_BIND_FAILURE: return Memcached::HostLookupFailure;
1665  case MEMCACHED_WRITE_FAILURE: return Memcached::WriteFailure;
1666  case MEMCACHED_READ_FAILURE: return Memcached::ReadFailure;
1667  case MEMCACHED_UNKNOWN_READ_FAILURE: return Memcached::UnknownReadFailure;
1668  case MEMCACHED_PROTOCOL_ERROR: return Memcached::ProtocolError;
1669  case MEMCACHED_CLIENT_ERROR: return Memcached::ClientError;
1670  case MEMCACHED_SERVER_ERROR: return Memcached::ServerError;
1671  case MEMCACHED_ERROR: return Memcached::Error;
1672  case MEMCACHED_DATA_EXISTS: return Memcached::DataExists;
1673  case MEMCACHED_DATA_DOES_NOT_EXIST: return Memcached::DataDoesNotExist;
1674  case MEMCACHED_NOTSTORED: return Memcached::NotStored;
1675  case MEMCACHED_STORED: return Memcached::Stored;
1676  case MEMCACHED_NOTFOUND: return Memcached::NotFound;
1677  case MEMCACHED_MEMORY_ALLOCATION_FAILURE: return Memcached::MemoryAllocationFailure;
1678  case MEMCACHED_PARTIAL_READ: return Memcached::PartialRead;
1679  case MEMCACHED_SOME_ERRORS: return Memcached::SomeErrors;
1680  case MEMCACHED_NO_SERVERS: return Memcached::NoServers;
1681  case MEMCACHED_END: return Memcached::End;
1682  case MEMCACHED_DELETED: return Memcached::Deleted;
1683  case MEMCACHED_STAT: return Memcached::Stat;
1684  case MEMCACHED_ERRNO: return Memcached::Errno;
1685  case MEMCACHED_NOT_SUPPORTED: return Memcached::NotSupported;
1686  case MEMCACHED_FETCH_NOTFINISHED: return Memcached::FetchNotFinished;
1687  case MEMCACHED_TIMEOUT: return Memcached::Timeout;
1688  case MEMCACHED_BUFFERED: return Memcached::Buffered;
1689  case MEMCACHED_BAD_KEY_PROVIDED: return Memcached::BadKeyProvided;
1690  case MEMCACHED_INVALID_HOST_PROTOCOL: return Memcached::InvalidHostProtocol;
1691  case MEMCACHED_SERVER_MARKED_DEAD: return Memcached::ServerMarkedDead;
1692  case MEMCACHED_UNKNOWN_STAT_KEY: return Memcached::UnknownStatKey;
1693  case MEMCACHED_E2BIG: return Memcached::E2Big;
1694  case MEMCACHED_INVALID_ARGUMENTS: return Memcached::InvalidArguments;
1695  case MEMCACHED_KEY_TOO_BIG: return Memcached::KeyTooBig;
1696  case MEMCACHED_AUTH_PROBLEM: return Memcached::AuthProblem;
1697  case MEMCACHED_AUTH_FAILURE: return Memcached::AuthFailure;
1698  case MEMCACHED_AUTH_CONTINUE: return Memcached::AuthContinue;
1699  case MEMCACHED_PARSE_ERROR: return Memcached::ParseError;
1700  case MEMCACHED_PARSE_USER_ERROR: return Memcached::ParseUserError;
1701  case MEMCACHED_DEPRECATED: return Memcached::Deprecated;
1702  case MEMCACHED_IN_PROGRESS: return Memcached::InProgress;
1703  case MEMCACHED_SERVER_TEMPORARILY_DISABLED: return Memcached::ServerTemporaryDisabled;
1704  case MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE: return Memcached::ServerMemoryAllocationFailure;
1705  case MEMCACHED_MAXIMUM_RETURN: return Memcached::MaximumReturn;
1706  default: return Memcached::Success;
1707  }
1708 }
1709 // clang-format on
1710 
1711 void MemcachedPrivate::setReturnType(Memcached::MemcachedReturnType *rt1, memcached_return_t rt2)
1712 {
1713  if (rt1) {
1714  *rt1 = MemcachedPrivate::returnTypeConvert(rt2);
1715  }
1716 }
1717 
1718 #include "moc_memcached.cpp"
static bool incrementByKey(const QString &groupKey, const QString &key, uint64_t offset, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:844
static bool incrementWithInitial(const QString &key, uint64_t offset, uint64_t initial, time_t expiration, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:885
static bool addByKey(const QString &groupKey, const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:422
static bool decrementWithInitialByKey(const QString &groupKey, const QString &key, uint64_t offset, uint64_t initial, time_t expiration, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1077
QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex)
static bool replace(const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:472
iterator insert(const Key &key, const T &value)
QString toUpper() const const
static bool flush(time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1246
void postForked(Cutelyst::Application *app)
virtual ~Memcached() override
Definition: memcached.cpp:29
void push_back(parameter_type value)
static bool replaceByKey(const QString &groupKey, const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:517
static bool increment(const QString &key, uint32_t offset, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:811
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
static bool casByKey(const QString &groupKey, const QString &key, const QByteArray &value, time_t expiration, uint64_t cas, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1170
static QString errorString(Context *c, MemcachedReturnType rt)
Definition: memcached.cpp:1514
void reserve(qsizetype size)
static bool touch(const QString &key, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1445
static bool flushBuffers(MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1222
void loadTranslations(const QString &filename, const QString &directory=QString(), const QString &prefix=QString(), const QString &suffix=QString())
QString join(QChar separator) const const
QString fromUtf8(QByteArrayView str)
Memcached(Application *parent)
Definition: memcached.cpp:23
static bool decrementByKey(const QString &groupKey, const QString &key, uint64_t offset, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1000
static QHash< QString, QByteArray > mgetByKey(const QString &groupKey, const QStringList &keys, QHash< QString, uint64_t > *casValues=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1349
static const time_t expirationNotAdd
Definition: memcached.h:691
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
static QByteArray get(const QString &key, uint64_t *cas=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:567
static bool existByKey(const QString &groupKey, const QString &key, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:779
static bool exist(const QString &key, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:751
qsizetype size() const const
T value(qsizetype i) const const
static QHash< QString, QByteArray > mget(const QStringList &keys, QHash< QString, uint64_t > *casValues=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1271
void setDefaultConfig(const QVariantMap &defaultConfig)
Definition: memcached.cpp:33
The Cutelyst Context.
Definition: context.h:38
bool empty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:290
bool isEmpty() const const
const char * constData() const const
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
Definition: context.cpp:490
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
static bool setByKey(const QString &groupKey, const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:327
static bool touchByKey(const QString &groupKey, const QString &key, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1475
static bool decrement(const QString &key, uint32_t offset, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:967
static bool removeByKey(const QString &groupKey, const QString &key, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:714
static bool remove(const QString &key, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:685
virtual bool setup(Application *app) override
Definition: memcached.cpp:39
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
const QChar at(qsizetype position) const const
static QVersionNumber libMemcachedVersion()
Returns the version of the currently used libmemcached.
Definition: memcached.cpp:1651
char * data()
static bool cas(const QString &key, const QByteArray &value, time_t expiration, uint64_t cas, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1123
The Cutelyst Application.
Definition: application.h:42
Engine * engine() const noexcept
static QByteArray getByKey(const QString &groupKey, const QString &key, uint64_t *cas=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:622
qsizetype size() const const
Cutelyst Memcached plugin.
Definition: memcached.h:157
static bool incrementWithInitialByKey(const QString &groupKey, const QString &key, uint64_t offset, uint64_t initial, time_t expiration, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:921
static bool add(const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:377
static bool decrementWithInitial(const QString &key, uint64_t offset, uint64_t initial, time_t expiration, uint64_t *value=nullptr, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:1041
static bool set(const QString &key, const QByteArray &value, time_t expiration, MemcachedReturnType *returnType=nullptr)
Definition: memcached.cpp:282
QByteArray toUtf8() const const