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