NCBI C++ ToolKit
netcache_search.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: netcache_search.cpp 99277 2023-03-03 22:30:04Z sadyrovr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Rafael Sadyrov
27  *
28  */
29 
30 
31 #include <ncbi_pch.hpp>
32 
33 #include <corelib/ncbistr.hpp>
34 #include <corelib/ncbidbg.hpp>
36 #include "netcache_api_impl.hpp"
37 
38 #include <ostream>
39 #include <list>
40 #include <limits>
41 
42 
43 namespace ncbi {
44 namespace grid {
45 namespace netcache {
46 namespace search {
47 
48 using namespace chrono;
49 
50 enum ETerm : size_t
51 {
61 
63 };
64 
65 enum EComparison : size_t
66 {
70 
72 };
73 
74 struct SCondition
75 {
76  SCondition(size_t key) : m_Key(key) {}
77  virtual ~SCondition() {}
78 
79  size_t Key() const { return m_Key; }
80 
81  virtual ostream& Output(ostream&) const = 0;
82  virtual void Merge(SCondition*) = 0;
83 
84  template <ETerm term, EComparison comparison, typename TValue>
85  static SCondition* Create(TValue);
86 
87 private:
88  size_t m_Key;
89 };
90 
91 ostream& operator<<(ostream& os, const SCondition& c)
92 {
93  return c.Output(os);
94 }
95 
96 template <ETerm term, EComparison comparison, typename TValue>
98 {
100  SCondition(comparison + static_cast<size_t>(term) * eNumberOfComparisons),
101  m_Value(value)
102  {
103  }
104 
105  ostream& Output(ostream& os) const override;
106  void Merge(SCondition*) override;
107 
108 private:
109  TValue m_Value;
110 };
111 
112 const char* s_Term(ETerm term)
113 {
114  switch (term) {
115  case eKey: return "key";
116  case eSubkey: return "subkey";
117  case eCreated: return "fcr_epoch";
118  case eCreatedAgo: return "fcr_ago";
119  case eExpires: return "fexp_epoch";
120  case eExpiresIn: return "fexp_now";
121  case eVersionExpires: return "fvexp_epoch";
122  case eVersionExpiresIn: return "fvexp_now";
123  case eSize: return "fsize";
124  default: return nullptr;
125  }
126 }
127 
128 const char* s_Comparison(EComparison comparison)
129 {
130  switch (comparison) {
131  case eLessThan: return "_lt";
132  case eEqual: return "";
133  case eGreaterOrEqual: return "_ge";
134  default: return nullptr;
135  }
136 }
137 
138 template <typename TValue>
139 string s_Value(TValue value)
140 {
141  return to_string(value);
142 }
143 
144 template <>
145 string s_Value(string value)
146 {
147  return value;
148 }
149 
150 template <ETerm term, EComparison comparison, typename TValue>
152 {
153  return os << s_Term(term) << s_Comparison(comparison) << "=" << s_Value(m_Value);
154 }
155 
156 template <ETerm term, EComparison comparison, typename TValue>
157 struct SMerge;
158 
159 template <ETerm term, typename TValue>
160 struct SMerge<term, eLessThan, TValue>
161 {
162  SMerge(TValue& left, const TValue& right)
163  {
164  if (left > right) left = right;
165  }
166 };
167 
168 template <ETerm term, typename TValue>
169 struct SMerge<term, eGreaterOrEqual, TValue>
170 {
171  SMerge(TValue& left, const TValue& right)
172  {
173  if (left < right) left = right;
174  }
175 };
176 
177 template <>
179 {
180  SMerge(string&, const string&)
181  {
182  NCBI_THROW_FMT(CNetCacheException, eNotImplemented,
183  "Field '" << s_Term(eKey) << "' cannot be specified more than once");
184  }
185 };
186 
187 template <ETerm term, EComparison comparison, typename TValue>
189 {
190  auto other = dynamic_cast<decltype(this)>(o);
191  _ASSERT(other);
192 
193  SMerge<term, comparison, TValue>(m_Value, other->m_Value);
194 }
195 
196 template <ETerm term, EComparison comparison, typename TValue>
198 {
200 }
201 
203 {
204  list<shared_ptr<SCondition>> conditions;
205 };
206 
208 {
209 }
210 
211 template <ETerm term, EComparison comparison, typename TValue>
213 {
214  auto condition = SCondition::Create<term, comparison>(value);
215 
217  result.impl.reset(new SExpressionImpl);
218  result.impl->conditions.emplace_back(condition);
219  return result;
220 }
221 
222 template <ETerm term, EComparison comparison, typename TValue>
224 {
226  result.base = s_CreateBase<term, comparison>(value);
227  return result;
228 }
229 
230 chrono::seconds::rep s_GetSeconds(duration d)
231 {
232  return duration_cast<chrono::seconds>(d).count();
233 }
234 
235 chrono::seconds::rep s_GetSeconds(time_point p)
236 {
237  return s_GetSeconds(p.time_since_epoch());
238 }
239 
241 {
242  return s_Create<eKey, eEqual>(v);
243 }
244 
246 {
247  return s_Create<eCreated, eGreaterOrEqual>(s_GetSeconds(v));
248 }
249 
251 {
252  return s_Create<eCreated, eLessThan>(s_GetSeconds(v));
253 }
254 
256 {
257  return s_Create<eCreatedAgo, eGreaterOrEqual>(s_GetSeconds(v));
258 }
259 
261 {
262  return s_Create<eCreatedAgo, eLessThan>(s_GetSeconds(v));
263 }
264 
266 {
267  return s_Create<eExpires, eGreaterOrEqual>(s_GetSeconds(v));
268 }
269 
271 {
272  return s_Create<eExpires, eLessThan>(s_GetSeconds(v));
273 }
274 
276 {
277  return s_Create<eExpiresIn, eGreaterOrEqual>(s_GetSeconds(v));
278 }
279 
281 {
282  return s_Create<eExpiresIn, eLessThan>(s_GetSeconds(v));
283 }
284 
286 {
287  return s_Create<eVersionExpires, eGreaterOrEqual>(s_GetSeconds(v));
288 }
289 
291 {
292  return s_Create<eVersionExpires, eLessThan>(s_GetSeconds(v));
293 }
294 
296 {
297  return s_Create<eVersionExpiresIn, eGreaterOrEqual>(s_GetSeconds(v));
298 }
299 
301 {
302  return s_Create<eVersionExpiresIn, eLessThan>(s_GetSeconds(v));
303 }
304 
306 {
307  return s_Create<eSize, eGreaterOrEqual>(v);
308 }
309 
311 {
312  return s_Create<eSize, eLessThan>(v);
313 }
314 
316 {
317  if (!l.impl) { l = r; return; }
318  if (!r.impl) return;
319 
320  auto& lc = l.impl->conditions;
321  auto& rc = r.impl->conditions;
322  auto li = lc.begin();
323  auto ri = rc.begin();
324 
325  while (li != lc.end() && ri != rc.end()) {
326  auto& lp = *li;
327  auto& rp = *ri;
328 
329  if (lp->Key() < rp->Key()) {
330  ++li;
331  } else if (lp->Key() > rp->Key()) {
332  auto old_ri = ri;
333  lc.splice(li, rc, old_ri, ++ri);
334  } else {
335  lp->Merge(rp.get());
336  ++li;
337  ++ri;
338  }
339  }
340 
341  if (ri != rc.end()) {
342  lc.splice(lc.end(), rc, ri, rc.end());
343  }
344 }
345 
347 {
348  s_Merge(l.base, r.base);
349  return l;
350 }
351 
353 {
354  s_Merge(l.base, r.base);
355  return l;
356 }
357 
358 ostream& operator<<(ostream& os, CExpression expression)
359 {
360  if (!expression.base.impl) return os;
361 
362  for (auto& condition : expression.base.impl->conditions) {
363  os << " " << *condition;
364  }
365 
366  return os;
367 }
368 
369 // Mirrored versions
370 CExpression operator==(string v, KEY t) { return t == v; }
373 CExpression operator<=(duration v, CREATED t) { return t >= v; }
377 CExpression operator<=(duration v, EXPIRES t) { return t >= v; }
383 CExpression operator<=(size_t v, SIZE t) { return t >= v; }
384 CExpression operator> (size_t v, SIZE t) { return t < v; }
385 
386 // Cannot use zero, as corresponding condition would be ignored then
387 const chrono::seconds::rep kSmallestTimePoint = 1;
389 
391 {
392 }
393 
396 {
397 }
398 
401 {
402 }
403 
406 {
407 }
408 
411 {
412 }
413 
415 {
416  s_Merge(l.base, r.base);
417  return l;
418 }
419 
421 {
422  string key;
423  string subkey;
424 
425  SBlobInfoImpl(string key, string subkey, string data);
429  size_t operator[](SIZE);
430 
431  static SBlobInfoImpl* Create(string data);
432 
433 private:
434  void Parse();
435 
436  const string m_Data;
437  bool m_Parsed;
442 };
443 
444 SBlobInfoImpl::SBlobInfoImpl(string k, string sk, string data)
445  : key(k),
446  subkey(sk),
447  m_Data(data),
448  m_Parsed(false)
449 {
450 }
451 
453 {
454  if (!m_Parsed) Parse();
455  return m_Created.GetValue();
456 }
457 
459 {
460  if (!m_Parsed) Parse();
461  return m_Expires.GetValue();
462 }
463 
465 {
466  if (!m_Parsed) Parse();
467  return m_VersionExpires.GetValue();
468 }
469 
471 {
472  if (!m_Parsed) Parse();
473  return m_Size.GetValue();
474 }
475 
476 const string kSeparator = "\t";
477 
478 pair<CTempString, CTempString> s_GetField(const string& data, size_t& pos)
479 {
480  size_t eq = data.find("=", pos);
481 
482  if (eq == string::npos) {
483  NCBI_THROW_FMT(CNetCacheException, eInvalidServerResponse, "Invalid response '" << data << "'");
484  }
485 
486  CTempString name(data, pos, eq - pos);
487 
488  pos = data.find(kSeparator, ++eq);
489 
490  if (pos == string::npos) pos = data.size();
491 
492  CTempString value(data, eq, pos++ - eq);
493 
494  return make_pair(name, value);
495 }
496 
498 {
499  for (size_t pos = 0; pos < m_Data.size(); ) {
500  const auto field = s_GetField(m_Data, pos);
501  const auto& name = field.first;
502  const auto& value = field.second;
503 
504  if (name == "cr_time") {
505  m_Created = time_point(seconds(NStr::StringToNumeric<seconds::rep>(value)));
506  } else if (name == "exp") {
507  m_Expires = time_point(seconds(NStr::StringToNumeric<seconds::rep>(value)));
508  } else if (name == "ver_dead") {
509  m_VersionExpires = time_point(seconds(NStr::StringToNumeric<seconds::rep>(value)));
510  } else if (name == "size") {
511  m_Size = NStr::StringToNumeric<size_t>(value);
512  } else {
513  NCBI_THROW_FMT(CNetCacheException, eInvalidServerResponse,
514  "Unknown field '" << name << "' in response '" << m_Data << "'");
515  }
516  }
517 
518  m_Parsed = true;
519 }
520 
521 void operator<<(CBlobInfo& blob_info, string data)
522 {
523  string cache, key, subkey, remaining;
524  NStr::SplitInTwo(data, kSeparator, cache, remaining);
525  NStr::SplitInTwo(remaining, kSeparator, key, remaining);
526  NStr::SplitInTwo(remaining, kSeparator, subkey, remaining);
527  blob_info.base.impl.reset(new SBlobInfoImpl(key, subkey, remaining));
528 }
529 
531 {
532 }
533 
535 {
536  if (!base.impl) return string();
537  return base.impl->key;
538 }
539 
541 {
542  if (!base.impl) return string();
543  return base.impl->subkey;
544 }
545 
547 {
548  if (!base.impl) return time_point();
549  return (*base.impl)[created];
550 }
551 
553 {
554  if (!base.impl) return time_point();
555  return (*base.impl)[expires];
556 }
557 
559 {
560  if (!base.impl) return time_point();
561  return (*base.impl)[version_expires];
562 }
563 
565 {
566  if (!base.impl) return size_t();
567  return (*base.impl)[size];
568 }
569 
570 }
571 }
572 }
573 }
#define false
Definition: bool.h:36
NetCache internal exception.
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
char value[7]
Definition: config.c:431
The NCBI C++ standard methods for dealing with std::string.
static int lc
Definition: getdata.c:30
const TValue & GetValue(void) const
Get a const reference to the current value.
Definition: ncbimisc.hpp:703
string
Definition: cgiapp.hpp:687
#define NCBI_THROW_FMT(exception_class, err_code, message)
The same as NCBI_THROW but with message processed as output to ostream.
Definition: ncbiexpt.hpp:719
CFields operator|(CFields, CFields)
CExpression operator<(CREATED, time_point)
CExpression operator>=(CREATED, time_point)
CExpression operator&&(CExpression, CExpression)
CExpression operator==(KEY, string)
CExpression operator>(time_point, CREATED)
CExpression operator<=(time_point, CREATED)
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3550
const struct ncbi::grid::netcache::search::fields::SIZE size
const struct ncbi::grid::netcache::search::fields::EXPIRES expires
const struct ncbi::grid::netcache::search::fields::CREATED created
const struct ncbi::grid::netcache::search::fields::KEY key
const struct ncbi::grid::netcache::search::fields::SUBKEY subkey
const struct ncbi::grid::netcache::search::fields::VERSION_EXPIRES version_expires
CExpression s_Create(TValue value)
const char * s_Term(ETerm term)
string s_Value(TValue value)
chrono::system_clock::time_point time_point
void s_Merge(SExpression &l, SExpression &r)
pair< CTempString, CTempString > s_GetField(const string &data, size_t &pos)
chrono::system_clock::duration duration
CExpression operator+(CExpression l, CFields r)
SExpression s_CreateBase(TValue value)
chrono::seconds::rep s_GetSeconds(duration d)
const char * s_Comparison(EComparison comparison)
const chrono::seconds::rep kSmallestTimePoint
ostream & operator<<(ostream &os, const SCondition &c)
Magic spell ;-) needed for some weird compilers... very empiric.
EIPRangeType t
Definition: ncbi_localip.c:101
NCBI C++ auxiliary debug macros.
bool eq(T x_, T y_, T round_)
Definition: njn_approx.hpp:79
T max(T x_, T y_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
Output fields specification.
static SBlobInfoImpl * Create(string data)
SBlobInfoImpl(string key, string subkey, string data)
ostream & Output(ostream &os) const override
virtual void Merge(SCondition *)=0
virtual ostream & Output(ostream &) const =0
list< shared_ptr< SCondition > > conditions
shared_ptr< SExpressionImpl > impl
#define _ASSERT
else result
Definition: token2.c:20
void Merge(wxMenu &menu_1, const wxMenu &menu_2)
merges all items form menu_2 into menu_1, preserving the structure if possible
Definition: wx_utils.cpp:579
Modified on Wed Nov 29 02:12:16 2023 by modify_doxy.py rev. 669887