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