Line data Source code
1 : /*
2 : * Text:
3 : * libsnapwebsites/src/libdbproxy/cell.cpp
4 : *
5 : * Description:
6 : * Handling of cell. There is no class representing a row in Cassandra.
7 : * A row is just a key. We have this object to allow for our C++ array
8 : * syntax to access the Cassandra data.
9 : *
10 : * Documentation:
11 : * See each function below.
12 : *
13 : * License:
14 : * Copyright (c) 2011-2019 Made to Order Software Corp. All Rights Reserved
15 : *
16 : * https://snapwebsites.org/
17 : * contact@m2osw.com
18 : *
19 : * Permission is hereby granted, free of charge, to any person obtaining a
20 : * copy of this software and associated documentation files (the
21 : * "Software"), to deal in the Software without restriction, including
22 : * without limitation the rights to use, copy, modify, merge, publish,
23 : * distribute, sublicense, and/or sell copies of the Software, and to
24 : * permit persons to whom the Software is furnished to do so, subject to
25 : * the following conditions:
26 : *
27 : * The above copyright notice and this permission notice shall be included
28 : * in all copies or substantial portions of the Software.
29 : *
30 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33 : * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34 : * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35 : * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36 : * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 : */
38 :
39 : #include "libdbproxy/cell.h"
40 : #include "libdbproxy/exception.h"
41 : #include "libdbproxy/row.h"
42 :
43 : #include <stdexcept>
44 : #include <iostream>
45 :
46 : namespace libdbproxy
47 : {
48 :
49 :
50 : /** \class cell
51 : * \brief A cell holds a name and value pair.
52 : *
53 : * A cell represents the value of a column in a row. The name of a cell
54 : * is the name of the corresponding column. The value is the data saved
55 : * in the Cassandra database.
56 : *
57 : * The name of the cell is kept as a binary key (it can be binary.) It
58 : * is limited it length to a little under 64Kb.
59 : *
60 : * Cells are loaded from the Cassandra database whenever the user
61 : * reads its value. Actually, the value is marked as cached once read
62 : * the first time. Each further access is done using the memory value
63 : * thus avoiding accessing the Cassandra server each time. Note that
64 : * may have some side effects if your process runs for a long time.
65 : * Use the cell, row, table, or context clearCache() functions to
66 : * palliate to this problem.
67 : *
68 : * Cells are saved to the Cassandra database whenever the user overwrite
69 : * its current value. In this case the cache is updated but the data is
70 : * non the less written to Cassandra except if the value was not modified
71 : * and the cache was marked as active.
72 : */
73 :
74 :
75 : /** \var cell::f_row
76 : * \brief A pointer back to the row onwer.
77 : *
78 : * This bare pointer back to the row owner is used whenever the value is
79 : * read (and not yet cached) or written. This way we can send the data
80 : * back to the Cassandra database.
81 : */
82 :
83 :
84 : /** \var cell::f_key
85 : * \brief The column name of this cell.
86 : *
87 : * This cell has a name paired with its value. This is the name part.
88 : * The key is saved in binary form only.
89 : */
90 :
91 :
92 : /** \var cell::f_cached
93 : * \brief Whether a cell is a cache.
94 : *
95 : * This flag mark the cell as being a cache for the value defined in it.
96 : * By default a cell is marked as not caching anything. It becomes a cached
97 : * value once the value was saved in the Cassandra database or read from
98 : * the Cassandra system.
99 : *
100 : * Note however that the cell is no aware of whether the table is a memory
101 : * or Cassandra table. As such, the cache flag may be lying.
102 : */
103 :
104 :
105 : /** \var cell::f_value
106 : * \brief A cell value.
107 : *
108 : * This member represents the value of this cell.
109 : *
110 : * Note that by default when you copy a cell value the value buffer itself
111 : * is not copied, instead it is shared. This is quite useful to avoid many
112 : * memory copies.
113 : */
114 :
115 :
116 : /** \brief Initialize a row object.
117 : *
118 : * This function initializes a cell object. You must specify the
119 : * key of the column.
120 : *
121 : * In this case, the key of the cell is a binary buffer of data. Remember
122 : * however that the column names that are not ASCII may cause problems
123 : * (i.e. with CQL and the Cassandra CLI.)
124 : *
125 : * A cell is set to the NULL value by default.
126 : *
127 : * \exception exception
128 : * The key of the column cannot be empty or more than 64Kb. If that happens,
129 : * this exception is raised.
130 : *
131 : * \param[in] row The parent row of this cell.
132 : * \param[in] column_key The binary key of this cell.
133 : */
134 0 : cell::cell(row::pointer_t row, const QByteArray& column_key)
135 : : f_row(row)
136 0 : , f_key(column_key)
137 : //, f_value() -- auto-init to "NULL" (nullValue() == true)
138 : {
139 0 : if(f_key.size() == 0) {
140 0 : throw exception("the cell binary column key cannot be empty");
141 : }
142 0 : if(f_key.size() > 65535) {
143 0 : throw exception("the cell binary column key is more than 64Kb");
144 : }
145 0 : }
146 :
147 :
148 : /** \brief Clean up the cell object.
149 : *
150 : * This function ensures that all resources allocated by the
151 : * cell are released.
152 : */
153 0 : cell::~cell()
154 : {
155 0 : }
156 :
157 :
158 : /** \brief Retrieve the name of the column.
159 : *
160 : * This function returns the name of the column as specified in the
161 : * constructor.
162 : *
163 : * The name cannot be changed.
164 : *
165 : * Note that if you created the cell with a binary key (i.e. a
166 : * QByteArray parameter) then you CANNOT retrieve the column name.
167 : * Instead, use the columnKey() function.
168 : *
169 : * \exception exception
170 : * This function raises an exception if the cell was created with
171 : * a binary key.
172 : *
173 : * \return A string with the column name.
174 : *
175 : * \sa rowKey()
176 : */
177 0 : QString cell::columnName() const
178 : {
179 0 : return QString::fromUtf8(f_key.data());
180 : }
181 :
182 :
183 : /** \brief Retrieve the column key.
184 : *
185 : * This function returns the column key of this cell. The key is a binary
186 : * buffer of data. This function works whether the cell was created with a
187 : * name or a key.
188 : *
189 : * Note that when creating a cell with a binary key, you cannot retrieve
190 : * it using the columnName() function.
191 : *
192 : * \return A buffer of data representing the column key.
193 : *
194 : * \sa columnName()
195 : */
196 0 : const QByteArray& cell::columnKey() const
197 : {
198 0 : return f_key;
199 : }
200 :
201 :
202 : /** \brief Retrieve the cell value.
203 : *
204 : * This function is used to retrieve the cell value.
205 : *
206 : * Note that the value gets cached. That means if you call the function
207 : * again, then the same value will be returned (although the setValue()
208 : * can be used to change the cached value.)
209 : *
210 : * To reset the cache, use the clearCache() function.
211 : *
212 : * \return The current value defined in the cell
213 : *
214 : * \sa clearCache()
215 : * \sa setValue()
216 : */
217 0 : const value& cell::getValue() const
218 : {
219 0 : if(!f_cached)
220 : {
221 0 : parentRow()->getValue( f_key, const_cast<value&>(f_value) );
222 0 : f_cached = true;
223 : }
224 0 : return f_value;
225 : }
226 :
227 :
228 : /** \brief Change the value.
229 : *
230 : * This function changes the value of this cell. If the cell is currently
231 : * attached to a table in the Cassandra server, then it is written to the
232 : * server except if the value does not change.
233 : *
234 : * In other words, we avoid sending the same value to the Cassandra server
235 : * over and over again. To force a write to the Cassandra server, call
236 : * the clearCache() function before the setValue() function.
237 : *
238 : * \todo
239 : * If setting a counter, "value" is save in the cache as is. This means
240 : * the value may be an integer of any size instead of being a 64 bit
241 : * integer.
242 : *
243 : * \note
244 : * When the values are compared, the timestamp is ignored.
245 : *
246 : * \param[in] value The new value for this cell.
247 : */
248 0 : void cell::setValue(const value& val)
249 : {
250 0 : if(!f_cached || f_value != val)
251 : {
252 : // TODO: if the cell represents a counter, it should be resized
253 : // to a 64 bit value to work in all places
254 0 : f_value = val;
255 0 : parentRow()->insertValue(f_key, f_value);
256 0 : f_cached = true;
257 : }
258 0 : }
259 :
260 :
261 : /** \brief Change the value as if read from Cassandra.
262 : *
263 : * This function assigns the specified value as if it had been read from
264 : * Cassandra. This way the Row can set a value it just read and avoid
265 : * another read() (or worse, a write!)
266 : *
267 : * The value is marked as cached meaning that it was read or written to
268 : * the Cassandra database.
269 : *
270 : * This generally happens when you call value(). There is a simplified
271 : * view of what happens (without the row, table,
272 : * libdbproxy, and Thrift shown):
273 : *
274 : * \msc
275 : * width=900;
276 : * cell,context,QCassandraPrivate,Cassandra;
277 : * cell:>context [label="getValue()"];
278 : * context=>QCassandraPrivate [label="getValue()"];
279 : * QCassandraPrivate->Cassandra [label="get()"];
280 : * ...;
281 : * Cassandra->QCassandraPrivate [label="return"];
282 : * |||;
283 : * cell abox QCassandraPrivate [label="if value returned from last get()"];
284 : * QCassandraPrivate=>cell [label="getValue()", linecolor="red"];
285 : * cell>>QCassandraPrivate [label="return"];
286 : * cell abox QCassandraPrivate [label="end if"];
287 : * |||;
288 : * QCassandraPrivate>>context [label="return"];
289 : * context:>cell [label="return"];
290 : * \endmsc
291 : *
292 : * Note that similar calls happen whenever you call row::readCells()
293 : * and table::readRows().
294 : *
295 : * \param[in] value The new value to assign to this cell.
296 : */
297 0 : void cell::assignValue(const value& val)
298 : {
299 0 : f_value = val;
300 0 : f_cached = true;
301 0 : }
302 :
303 :
304 : /** \brief Set the cell value.
305 : *
306 : * This function is called whenever you write a value to the Cassandra
307 : * database using the array syntax such as:
308 : *
309 : * \code
310 : * cluster["context"]["table"]["row"]["column"] = value;
311 : * \endcode
312 : *
313 : * Note that the value gets cached. That means if you call a getValue()
314 : * function, you get a copy of the value you saved here.
315 : *
316 : * To reset the cache, use the clearCache() function.
317 : *
318 : * \param[in] value The new cell value.
319 : *
320 : * \return A reference to this cell.
321 : *
322 : * \sa clearCache()
323 : * \sa setValue()
324 : */
325 0 : cell& cell::operator = (const value& val)
326 : {
327 0 : setValue(val);
328 0 : return *this;
329 : }
330 :
331 :
332 : /** \brief Retrieve the cell value.
333 : *
334 : * This function is called whenever you read a value from the Cassandra
335 : * database using the array syntax such as:
336 : *
337 : * \code
338 : * value value = cluster["context"]["table"]["row"]["column"];
339 : * \endcode
340 : *
341 : * Note that the value gets cached. That means if you call the function
342 : * again, then the same value will be returned (although the setValue()
343 : * can be used to change the cached value.)
344 : *
345 : * To reset the cache, use the clearCache() function.
346 : *
347 : * \return The current value defined in the cell
348 : *
349 : * \sa clearCache()
350 : * \sa setValue()
351 : */
352 0 : cell::operator value () const
353 : {
354 0 : return value();
355 : }
356 :
357 :
358 : /** \brief Add a value to a counter.
359 : *
360 : * This function is used to add a value to a counter.
361 : *
362 : * The current cell value is expected to be 8 bytes, although we support
363 : * 1, 2, 4, and 8 byte integers. The result is saved back in this cell as
364 : * a 64 bits value (8 bytes).
365 : *
366 : * \param[in] value The value to add to the counter. It may be negative.
367 : *
368 : * \return The expected value defined in the cell.
369 : */
370 0 : void cell::add(int64_t val)
371 : {
372 : // if cached, we update the value in memory as it is expected to be
373 0 : if(!f_value.nullValue())
374 : {
375 : // if the value is not defined, we'd have to read it before we can
376 : // increment it in memory; for this reason we don't do it at this point
377 0 : int64_t r(0);
378 0 : switch(f_value.size())
379 : {
380 0 : case 8:
381 0 : r = f_value.int64Value() + val;
382 0 : break;
383 :
384 0 : case 4:
385 0 : r = f_value.int32Value() + val;
386 0 : break;
387 :
388 0 : case 2:
389 0 : r = f_value.int16Value() + val;
390 0 : break;
391 :
392 0 : case 1:
393 0 : r = f_value.signedCharValue() + val;
394 0 : break;
395 :
396 0 : default:
397 0 : throw exception("a counter cell is expected to be an 8, 16, 32, or 64 bit value");
398 :
399 : }
400 0 : f_value.setInt64Value(r);
401 0 : f_cached = true;
402 : }
403 :
404 0 : parentRow()->insertValue( f_key, f_value );
405 0 : }
406 :
407 :
408 : /** \brief Add to a counter.
409 : *
410 : * This operator adds a value to a counter.
411 : *
412 : * \code
413 : * cluster["context"]["table"]["row"]["column"] += 5;
414 : * \endcode
415 : *
416 : * Note that the resulting value gets cached. That means if reading the value
417 : * after this call, the cached value is returned. To reset the cache, use
418 : * the clearCache() function.
419 : *
420 : * \warning
421 : * The value in the cell after this call is an approximation of the counter
422 : * value. The operator does not read the most current value.
423 : *
424 : * \param[in] value The value to add to the existing value of this cell.
425 : *
426 : * \return A reference to this Cassandra cell.
427 : *
428 : * \sa clearCache()
429 : * \sa add()
430 : */
431 0 : cell& cell::operator += (int64_t val)
432 : {
433 0 : add(val);
434 0 : return *this;
435 : }
436 :
437 :
438 : /** \brief Increment a counter.
439 : *
440 : * This operator is used to add one to a counter.
441 : *
442 : * \code
443 : * ++cluster["context"]["table"]["row"]["column"];
444 : * \endcode
445 : *
446 : * \return A reference to this Cassandra cell.
447 : *
448 : * \sa add()
449 : * \sa operator + ()
450 : */
451 0 : cell& cell::operator ++ ()
452 : {
453 0 : add(1);
454 0 : return *this;
455 : }
456 :
457 :
458 : /** \brief Increment a counter.
459 : *
460 : * This operator is used to add one to a counter.
461 : *
462 : * \code
463 : * cluster["context"]["table"]["row"]["column"]++;
464 : * \endcode
465 : *
466 : * \warning
467 : * Note that this operator returns this cell and not
468 : * a copy because we cannot create a copy of the cell.
469 : *
470 : * \return A reference to this Cassandra cell.
471 : *
472 : * \sa add()
473 : * \sa operator + ()
474 : */
475 : //cell& cell::operator ++ (int)
476 : //{
477 : // add(1);
478 : // return *this;
479 : //}
480 :
481 :
482 : /** \brief Subtract from a counter.
483 : *
484 : * This operator subtract a value from a counter.
485 : *
486 : * \code
487 : * cluster["context"]["table"]["row"]["column"] -= 9;
488 : * \endcode
489 : *
490 : * Note that the resulting value gets cached. That means if reading the value
491 : * after this call, the cached value is returned. To reset the cache, use
492 : * the clearCache() function.
493 : *
494 : * \warning
495 : * The value in the cell after this call is an approximation of the counter
496 : * value. The operator does not read the most current value.
497 : *
498 : * \param[in] value The value to subtract from the current content of the cell.
499 : *
500 : * \return A reference to this Cassandra cell.
501 : *
502 : * \sa clearCache()
503 : * \sa add()
504 : */
505 0 : cell& cell::operator -= (int64_t val)
506 : {
507 0 : add(-val);
508 0 : return *this;
509 : }
510 :
511 :
512 : /** \brief Decrement a counter.
513 : *
514 : * This operator is used to subtract one from a counter.
515 : *
516 : * \code
517 : * --cluster["context"]["table"]["row"]["column"];
518 : * \endcode
519 : *
520 : * \return A reference to this Cassandra cell.
521 : *
522 : * \sa add()
523 : * \sa operator - ()
524 : */
525 0 : cell& cell::operator -- ()
526 : {
527 0 : add(-1);
528 0 : return *this;
529 : }
530 :
531 :
532 : /** \brief Decrement a counter.
533 : *
534 : * This operator is used to subtract one from a counter.
535 : *
536 : * \code
537 : * cluster["context"]["table"]["row"]["column"]--;
538 : * \endcode
539 : *
540 : * \warning
541 : * Note that this operator returns this cell and not
542 : * a copy because we cannot create a copy of the cell.
543 : *
544 : * \return A reference to this Cassandra cell.
545 : *
546 : * \sa add()
547 : * \sa operator - ()
548 : */
549 : //cell& cell::operator -- (int)
550 : //{
551 : // add(-1);
552 : // return *this;
553 : //}
554 :
555 :
556 : /** \brief Retrieve the current consistency level of this value.
557 : *
558 : * This function returns the consistency level of this value. By default
559 : * it is set to one (CONSISTENCY_LEVEL_ONE.)
560 : *
561 : * The consistency level can be set using the setConsistencyLevel() function.
562 : *
563 : * \return The consistency level of this value.
564 : *
565 : * \sa setConsistencyLevel()
566 : * \sa value::consistencyLevel()
567 : */
568 0 : consistency_level_t cell::consistencyLevel() const
569 : {
570 0 : return f_value.consistencyLevel();
571 : }
572 :
573 :
574 : /** \brief Define the consistency level of this cell.
575 : *
576 : * This function sets the consistency of the f_value field of this cell.
577 : * This can be used to ensure the proper consistency on a read. In case
578 : * of a write, the consistency is always taken from the input value
579 : * parameter. For a read this is the only way to specify the consistency.
580 : *
581 : * By default, the consistency level is set to CONSISTENCY_LEVEL_DEFAULT
582 : * which means: use the consistency level defined in the libdbproxy object
583 : * linked with this cell. It is possible to set the consistency level
584 : * back to CONSISTENCY_LEVEL_DEFAULT.
585 : *
586 : * \param[in] level The new consistency level for this cell next read.
587 : *
588 : * \sa consistencyLevel()
589 : * \sa value::setConsistencyLevel()
590 : */
591 0 : void cell::setConsistencyLevel(consistency_level_t level)
592 : {
593 0 : f_value.setConsistencyLevel(level);
594 0 : }
595 :
596 :
597 : /** \brief The value of a cell is automatically cached in memory.
598 : *
599 : * This function can be used to mark that the currently cached
600 : * value need to be reset on the next call to the value
601 : * casting operator.
602 : *
603 : * However, note that the data of the cell is NOT released by this
604 : * call. To release the data, look into clearing the row cache
605 : * instead.
606 : *
607 : * \note
608 : * Setting a cell to the null value (i.e. value.setNullValue()) will
609 : * clear the data in the Cassandra database too. So don't use that
610 : * function to clear the data from memory!
611 : *
612 : * \sa row::clearCache()
613 : */
614 0 : void cell::clearCache()
615 : {
616 0 : f_cached = false;
617 0 : f_value.setNullValue();
618 0 : }
619 :
620 :
621 : #if 0
622 : /** \brief Retrieve the current timestamp of this cell value.
623 : *
624 : * This function returns the timestamp of the value variable member defined
625 : * in the cell. This value may be incorrect if the value wasn't read from
626 : * the Cassandra database or was never set with setTimestamp().
627 : *
628 : * \return The timestamp 64bit value.
629 : *
630 : * \sa setTimestamp()
631 : * \sa value::timestamp()
632 : */
633 : int64_t cell::timestamp() const
634 : {
635 : return f_value.timestamp();
636 : }
637 :
638 : /** \brief Define your own timestamp for this cell value.
639 : *
640 : * Set the timestamp of the value variable member of this cell.
641 : *
642 : * \param[in] timestamp The time used to mark this value.
643 : *
644 : * \sa timestamp()
645 : * \sa value::setTimestamp()
646 : */
647 : void cell::setTimestamp(int64_t val)
648 : {
649 : f_value.setTimestamp(val);
650 : }
651 : #endif
652 :
653 :
654 : /** \brief Get the pointer to the parent object.
655 : *
656 : * \return Shared pointer to the cassandra object.
657 : */
658 0 : row::pointer_t cell::parentRow() const
659 : {
660 0 : row::pointer_t row(f_row.lock());
661 0 : if(row == nullptr)
662 : {
663 0 : throw exception("this cell was dropped and is not attached to a row anymore");
664 : }
665 :
666 0 : return row;
667 : }
668 :
669 :
670 6 : } // namespace libdbproxy
671 : // vim: ts=4 sw=4 et
|