LCOV - code coverage report
Current view: top level - libdbproxy - context.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 128 0.8 %
Date: 2019-12-15 17:13:15 Functions: 2 23 8.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Text:
       3             :  *      libsnapwebsites/src/libdbproxy/context.cpp
       4             :  *
       5             :  * Description:
       6             :  *      Handling of Cassandra Keyspace which is a context.
       7             :  *
       8             :  * Documentation:
       9             :  *      See each function below.
      10             :  *
      11             :  * License:
      12             :  *      Copyright (c) 2011-2019  Made to Order Software Corp.  All Rights Reserved
      13             :  *
      14             :  *      https://snapwebsites.org/
      15             :  *      contact@m2osw.com
      16             :  *
      17             :  *      Permission is hereby granted, free of charge, to any person obtaining a
      18             :  *      copy of this software and associated documentation files (the
      19             :  *      "Software"), to deal in the Software without restriction, including
      20             :  *      without limitation the rights to use, copy, modify, merge, publish,
      21             :  *      distribute, sublicense, and/or sell copies of the Software, and to
      22             :  *      permit persons to whom the Software is furnished to do so, subject to
      23             :  *      the following conditions:
      24             :  *
      25             :  *      The above copyright notice and this permission notice shall be included
      26             :  *      in all copies or substantial portions of the Software.
      27             :  *
      28             :  *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      29             :  *      OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      30             :  *      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      31             :  *      IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      32             :  *      CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      33             :  *      TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      34             :  *      SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      35             :  */
      36             : 
      37             : #include "libdbproxy/context.h"
      38             : #include "libdbproxy/libdbproxy.h"
      39             : 
      40             : #include "snapwebsites/log.h"
      41             : 
      42             : #include <casswrapper/schema.h>
      43             : 
      44             : #include <stdexcept>
      45             : #include <unistd.h>
      46             : 
      47             : #include <sstream>
      48             : 
      49             : #include <QtCore>
      50             : //#include <QDebug>
      51             : 
      52             : 
      53             : namespace libdbproxy
      54             : {
      55             : 
      56             : /** \class context
      57             :  * \brief Hold a Cassandra keyspace definition.
      58             :  *
      59             :  * This class defines objects that can hold all the necessary information
      60             :  * for a Cassandra keyspace definition.
      61             :  *
      62             :  * A keyspace is similar to a context in the sense that to work on a keyspace
      63             :  * you need to make it the current context. Whenever you use a context, this
      64             :  * class automatically makes it the current context. This works well in a non
      65             :  * threaded environment. In a threaded environment, you want to either make
      66             :  * sure that only one thread makes use of the Cassandra objects or that you
      67             :  * protect all the calls. This library does not.
      68             :  *
      69             :  * You may think of this context as one database of an SQL environment. If
      70             :  * you have used OpenGL, this is very similar to the OpenGL context.
      71             :  */
      72             : 
      73             : /** \typedef context::QCassandraContextOptions
      74             :  * \brief A map of context options.
      75             :  *
      76             :  * This map defines options as name / value pairs.
      77             :  *
      78             :  * Only known otion names should be used or a protocol error may result.
      79             :  */
      80             : 
      81             : /** \var context::f_schema
      82             :  * \brief The pointer to the casswrapper::schema meta object.
      83             :  *
      84             :  * This pointer is a shared pointer to the private definition of
      85             :  * the Cassandra context (i.e. a keyspace definition.)
      86             :  *
      87             :  * The pointer is created at the time the context is created.
      88             :  */
      89             : 
      90             : /** \var context::f_cassandra
      91             :  * \brief A pointer back to the libdbproxy object.
      92             :  *
      93             :  * The bare pointer is used by the context to access the cassandra
      94             :  * private object and make the context the current context. It is
      95             :  * a bare pointer because the libdbproxy object cannot be deleted
      96             :  * without the context getting deleted first.
      97             :  *
      98             :  * Note that when deleting a context object, you may still
      99             :  * have a shared pointer referencing the object. This means the
     100             :  * object itself will not be deleted. In that case, the f_cassandra
     101             :  * parameter becomes NULL and calling functions that make use of
     102             :  * it throw an error.
     103             :  *
     104             :  * \note
     105             :  * If you look at the implementation, many functions call the
     106             :  * makeCurrent() which checks the f_cassandra pointer, thus these
     107             :  * functions don't actually test the pointer.
     108             :  */
     109             : 
     110             : /** \var context::f_tables
     111             :  * \brief List of tables.
     112             :  *
     113             :  * A list of the tables defined in this context. The tables may be created
     114             :  * in memory only.
     115             :  *
     116             :  * The list is a map using the table binary key as the its own key.
     117             :  */
     118             : 
     119             : /** \brief Initialize a context object.
     120             :  *
     121             :  * This function initializes a context object.
     122             :  *
     123             :  * Note that the constructor is private. To create a new context, you must
     124             :  * use the libdbproxy::context() function.
     125             :  *
     126             :  * All the parameters are set to the defaults as defined in the Cassandra
     127             :  * definition of the KsDef message. You can use the different functions to
     128             :  * change the default values.
     129             :  *
     130             :  * A context name must be composed of letters (A-Za-z), digits (0-9) and
     131             :  * underscore (_). It must start with a letter. The corresponding lexical
     132             :  * expression is: /[A-Za-z][A-Za-z0-9_]*\/
     133             :  *
     134             :  * \note
     135             :  * A context can be created, updated, and dropped. In all those cases, the
     136             :  * functions return once the Cassandra instance with which you are
     137             :  * connected is ready.
     138             :  *
     139             :  * \param[in] cassandra  The libdbproxy object owning this context.
     140             :  * \param[in] context_name  The name of the Cassandra context.
     141             :  *
     142             :  * \sa contextName()
     143             :  * \sa libdbproxy::context()
     144             :  */
     145           0 : context::context(libdbproxy::pointer_t cassandra, const QString& context_name)
     146             :     //: f_schema() -- auto-init
     147             :     : f_cassandra(cassandra)
     148           0 :     , f_context_name(context_name)
     149             :       //f_tables() -- auto-init
     150             : {
     151             :     // verify the name here (faster than waiting for the server and good documentation)
     152           0 :     QRegExp re("[A-Za-z][A-Za-z0-9_]*");
     153           0 :     if(!re.exactMatch(context_name))
     154             :     {
     155           0 :         throw exception("invalid context name (does not match [A-Za-z][A-Za-z0-9_]*)");
     156             :     }
     157             : 
     158           0 :     resetSchema();
     159           0 : }
     160             : 
     161             : /** \brief Clean up the context object.
     162             :  *
     163             :  * This function ensures that all resources allocated by the
     164             :  * context are released.
     165             :  *
     166             :  * Note that does not in any way destroy the context in the
     167             :  * Cassandra cluster.
     168             :  */
     169           0 : context::~context()
     170             : {
     171           0 : }
     172             : 
     173             : 
     174           0 : void context::resetSchema()
     175             : {
     176           0 :     f_schema = std::make_shared<casswrapper::schema::KeyspaceMeta>( f_context_name );
     177             : 
     178           0 :     casswrapper::schema::Value replication;
     179           0 :     auto& replication_map(replication.map());
     180           0 :     replication_map["class"]              = QVariant("SimpleStrategy");
     181           0 :     replication_map["replication_factor"] = QVariant(1);
     182             : 
     183           0 :     auto& field_map(f_schema->getFields());
     184           0 :     field_map["replication"]    = replication;
     185           0 :     field_map["durable_writes"] = QVariant(true);
     186           0 : }
     187             : 
     188             : 
     189             : /** \brief Retrieve the name of this context.
     190             :  *
     191             :  * This function returns the name of this context.
     192             :  *
     193             :  * Note that the name cannot be modified. It is set by the constructor as
     194             :  * you create a context.
     195             :  *
     196             :  * \return A QString with the context name.
     197             :  */
     198           0 : const QString& context::contextName() const
     199             : {
     200           0 :     return f_context_name;
     201             : }
     202             : 
     203             : 
     204           0 : const casswrapper::schema::Value::map_t& context::fields() const
     205             : {
     206           0 :     return f_schema->getFields();
     207             : }
     208             : 
     209             : 
     210           0 : casswrapper::schema::Value::map_t& context::fields()
     211             : {
     212           0 :     return f_schema->getFields();
     213             : }
     214             : 
     215             : 
     216             : /** \brief Retrieve a table definition by name.
     217             :  *
     218             :  * This function is used to retrieve a table definition by name.
     219             :  * If the table doesn't exist, it gets created.
     220             :  *
     221             :  * Note that if the context is just a memory context (i.e. it does not yet
     222             :  * exist in the Cassandra cluster,) then the table is just created in memory.
     223             :  * This is useful to create a new context with all of its tables all at
     224             :  * once. The process is to call the libdbproxy::context() function to get
     225             :  * an in memory context, and then call this table() function for each one of
     226             :  * the table you want to create. Finally, to call the create() function to
     227             :  * actually create the context and its table in the Cassandra cluster.
     228             :  *
     229             :  * You can test whether the result is null with the isNull() function
     230             :  * of the std::shared_ptr<> class.
     231             :  *
     232             :  * \note
     233             :  * In the old days, I used this function to get a table and prepare it to
     234             :  * add it to the Cassandra cluster. Now that doesn't work right because
     235             :  * the table description is missing in the situation where the table doesn't
     236             :  * exist yet in the database. You must call the createTable() instead for
     237             :  * now.
     238             :  *
     239             :  * \param[in] table_name  The name of the table to retrieve.
     240             :  *
     241             :  * \return A shared pointer to the table definition found or a null shared pointer.
     242             :  */
     243           0 : table::pointer_t context::getTable(const QString& table_name)
     244             : {
     245           0 :     table::pointer_t t( findTable( table_name ) );
     246           0 :     if( t != nullptr )
     247             :     {
     248           0 :         return t;
     249             :     }
     250             : 
     251             :     // this is a new table, allocate it
     252           0 :     t.reset( new table(shared_from_this(), table_name) );
     253           0 :     f_tables.insert( table_name, t );
     254           0 :     return t;
     255             : }
     256             : 
     257             : 
     258             : /** \brief Create a new table in Cassandra.
     259             :  *
     260             :  * In the old days, we could use the getTable() for both functions, but
     261             :  * the newer version requires a call to the parseTableDefinition() function
     262             :  * to make things work properly and get the table in Cassandra. Making
     263             :  * that call in the getTable() causes problems so instead I created this
     264             :  * function. I don't think this is 100% correct, but for now it works.
     265             :  * So this function as a whole is a TBD.
     266             :  *
     267             :  * Note that if the table already exists, then this function doesn't
     268             :  * hurt. It won't try to re-create the table.
     269             :  *
     270             :  * To make the table permanent in the Cassandra cluster, you must still
     271             :  * call the table->create() function after you setup the various parameters
     272             :  * (i.e. compression, compaction, GC, etc.)
     273             :  *
     274             :  * \param[in] table_name  The name of the table to create.
     275             :  *
     276             :  * \return A pointer to the new Cassandra table.
     277             :  */
     278           0 : table::pointer_t context::createTable(const QString& table_name)
     279             : {
     280           0 :     table::pointer_t t( findTable( table_name ) );
     281           0 :     if( t != nullptr )
     282             :     {
     283           0 :         return t;
     284             :     }
     285             : 
     286             :     // this is a new table, allocate it
     287           0 :     t.reset( new table(shared_from_this(), table_name) );
     288           0 :     f_tables.insert( table_name, t );
     289           0 :     t->parseTableDefinition(f_schema->createTable(table_name));
     290           0 :     return t;
     291             : }
     292             : 
     293             : 
     294             : /** \brief Retrieve a reference to the tables.
     295             :  *
     296             :  * This function retrieves a constant reference to the map of table definitions.
     297             :  * The list is read-only, however, it is strongly suggested that you make a copy
     298             :  * if your code is going to modifiy tables later (i.e. calling table() may
     299             :  * affect the result of this call if you did not first copy the map.)
     300             :  *
     301             :  * \return A reference to the table definitions of this context.
     302             :  */
     303           0 : const tables& context::getTables()
     304             : {
     305             : #if 0
     306             :     if( f_tables.empty() )
     307             :     {
     308             :         loadTables();
     309             :     }
     310             : #endif
     311             : 
     312           0 :     return f_tables;
     313             : }
     314             : 
     315             : /** \brief Search for a table.
     316             :  *
     317             :  * This function searches for a table. If it exists, its shared pointer is
     318             :  * returned. Otherwise, it returns a NULL pointer (i.e. the
     319             :  * std::shared_ptr<>::operator bool() function returns true.)
     320             :  *
     321             :  * \note
     322             :  * Since the system reads the list of existing tables when it starts, this
     323             :  * function returns tables that exist in the database and in memory only.
     324             :  *
     325             :  * \param[in] table_name  The name of the table to retrieve.
     326             :  *
     327             :  * \return A shared pointer to the table.
     328             :  */
     329           0 : table::pointer_t context::findTable(const QString& table_name)
     330             : {
     331             : #if 0
     332             :     if( f_tables.empty() )
     333             :     {
     334             :         loadTables();
     335             :     }
     336             : #endif
     337             : 
     338           0 :     tables::const_iterator it(f_tables.find(table_name));
     339           0 :     if(it == f_tables.end())
     340             :     {
     341           0 :         return table::pointer_t();
     342             :     }
     343           0 :     return *it;
     344             : }
     345             : 
     346             : /** \brief Retrieve a table reference from a context.
     347             :  *
     348             :  * The array operator searches for a table by name and returns
     349             :  * its reference. This is useful to access data with array like
     350             :  * syntax as in:
     351             :  *
     352             :  * \code
     353             :  * context[table_name][column_name] = value;
     354             :  * \endcode
     355             :  *
     356             :  * \exception exception
     357             :  * If the table doesn't exist, this function raises an exception
     358             :  * since otherwise the reference would be a NULL pointer.
     359             :  *
     360             :  * \param[in] table_name  The name of the table to retrieve.
     361             :  *
     362             :  * \return A reference to the named table.
     363             :  */
     364           0 : table& context::operator [] (const QString& table_name)
     365             : {
     366           0 :     table::pointer_t ptable( findTable(table_name) );
     367           0 :     if( !ptable ) {
     368           0 :         throw exception("named table was not found, cannot return a reference");
     369             :     }
     370             : 
     371           0 :     return *ptable;
     372             : }
     373             : 
     374             : 
     375             : #if 0
     376             : /** \brief Set the replication factor.
     377             :  *
     378             :  * This function sets the replication factor of the context.
     379             :  *
     380             :  * \deprecated
     381             :  * Since version 1.1 of Cassandra, the context replication
     382             :  * factor is viewed as a full option. This function automatically
     383             :  * sets the factor using the setDescriptionOption() function.
     384             :  * This means calling the setDescriptionOptions()
     385             :  * and overwriting all the options has the side effect of
     386             :  * cancelling this call. Note that may not work right with
     387             :  * older version of Cassandra. Let me know if that's the case.
     388             :  *
     389             :  * \param[in] factor  The new replication factor.
     390             :  */
     391             : void context::setReplicationFactor(int32_t factor)
     392             : {
     393             :     // since version 1.1 of Cassandra, the replication factor
     394             :     // defined in the structure is ignored
     395             :     QString value(QString("%1").arg(factor));
     396             :     setDescriptionOption("replication_factor", value);
     397             : }
     398             : 
     399             : /** \brief Unset the replication factor.
     400             :  *
     401             :  * This function unsets the replication factor in case it was set.
     402             :  * In general it is not necessary to call this function unless you
     403             :  * are initializing a new context and you want to make sure that
     404             :  * the default replication factor is used.
     405             :  */
     406             : void context::unsetReplicationFactor()
     407             : {
     408             :     eraseDescriptionOption("replication_factor");
     409             : }
     410             : 
     411             : /** \brief Check whether the replication factor is defined.
     412             :  *
     413             :  * This function retrieves the current status of the replication factor parameter.
     414             :  *
     415             :  * \return True if the replication factor parameter is defined.
     416             :  */
     417             : bool context::hasReplicationFactor() const
     418             : {
     419             :     return f_private->__isset.replication_factor;
     420             : }
     421             : 
     422             : /** \brief Retrieve the current replication factor.
     423             :  *
     424             :  * This function reads and return the current replication factor of
     425             :  * the context.
     426             :  *
     427             :  * If the replication factor is not defined, zero is returned.
     428             :  *
     429             :  * \return The current replication factor.
     430             :  */
     431             : int32_t context::replicationFactor() const
     432             : {
     433             :     if(f_private->__isset.replication_factor) {
     434             :         return f_private->replication_factor;
     435             :     }
     436             :     return 0;
     437             : }
     438             : 
     439             : /** \brief Set whether the writes are durable.
     440             :  *
     441             :  * Temporary and permanent contexts can be created. This option defines
     442             :  * whether it is one of the other. Set to true to create a permanent
     443             :  * context (this is the default.)
     444             :  *
     445             :  * \param[in] durable_writes  Set whether writes are durable.
     446             :  */
     447             : void context::setDurableWrites(bool durable_writes)
     448             : {
     449             :     f_private->__set_durable_writes(durable_writes);
     450             : }
     451             : 
     452             : /** \brief Unset the durable writes flag.
     453             :  *
     454             :  * This function marks the durable write flag as not set. This does
     455             :  * not otherwise change the flag. It will just not be sent over the
     456             :  * network and the default will be used when required.
     457             :  */
     458             : void context::unsetDurableWrites()
     459             : {
     460             :     f_private->__isset.durable_writes = false;
     461             : }
     462             : 
     463             : /** \brief Check whether the durable writes is defined.
     464             :  *
     465             :  * This function retrieves the current status of the durable writes parameter.
     466             :  *
     467             :  * \return True if the durable writes parameter is defined.
     468             :  */
     469             : bool context::hasDurableWrites() const
     470             : {
     471             :     return f_private->__isset.durable_writes;
     472             : }
     473             : 
     474             : /** \brief Retrieve the durable write flag.
     475             :  *
     476             :  * This function returns the durable flag that determines whether a
     477             :  * context is temporary (false) or permanent (true).
     478             :  *
     479             :  * \return The current durable writes flag status.
     480             :  */
     481             : bool context::durableWrites() const
     482             : {
     483             :     if(f_private->__isset.durable_writes) {
     484             :         return f_private->durable_writes;
     485             :     }
     486             :     return false;
     487             : }
     488             : 
     489             : 
     490             : /** \brief Prepare the context.
     491             :  *
     492             :  * This function prepares the context so it can be copied in a
     493             :  * keyspace definition later used to create a keyspace or to
     494             :  * update an existing keyspace.
     495             :  *
     496             :  * \todo
     497             :  * Verify that the strategy options are properly defined for the strategy
     498             :  * class (i.e. the "replication_factor" parameter is only for SimpleStrategy
     499             :  * and a list of at least one data center for other strategies.) However,
     500             :  * I'm not 100% sure that this is good idea since a user may add strategies
     501             :  * that we do not know anything about!
     502             :  *
     503             :  * \param[out] data  The output keyspace definition.
     504             :  *
     505             :  * \sa parseContextDefinition()
     506             :  */
     507             : void context::prepareContextDefinition(KsDef *ks) const
     508             : {
     509             :     *ks = *f_private;
     510             : 
     511             :     if(ks->strategy_class == "") {
     512             :         ks->strategy_class = "LocalStrategy";
     513             :     }
     514             : 
     515             :     // copy the options
     516             :     ks->strategy_options.clear();
     517             :     for(QCassandraContextOptions::const_iterator
     518             :                 o = f_options.begin(); o != f_options.end(); ++o)
     519             :     {
     520             :         ks->strategy_options.insert(
     521             :                 std::pair<std::string, std::string>(o.key().toUtf8().data(),
     522             :                                                     o.value().toUtf8().data()));
     523             :     }
     524             :     ks->__isset.strategy_options = !ks->strategy_options.empty();
     525             : 
     526             :     // copy the tables -- apparently we cannot do that here!
     527             :     // instead we have to loop through the table in the previous
     528             :     // level and update each column family separately
     529             :     ks->cf_defs.clear();
     530             :     for( auto t : f_tables )
     531             :     {
     532             :         CfDef cf;
     533             :         t->prepareTableDefinition(&cf);
     534             :         ks->cf_defs.push_back(cf);
     535             :     }
     536             :     //if(ks->cf_defs.empty()) ... problem? it's not optional...
     537             : }
     538             : 
     539             : 
     540             : /** \brief Generate the replication stanza for the CQL keyspace schema.
     541             :  */
     542             : QString context::generateReplicationStanza() const
     543             : {
     544             :     QString replication_stanza;
     545             :     if( f_private->strategy_class == "SimpleStrategy" )
     546             :     {
     547             :         replication_stanza = QString("'class': 'SimpleStrategy', 'replication_factor' : %1")
     548             :                              .arg(f_options["replication_factor"]);
     549             :     }
     550             :     else if( f_private->strategy_class == "NetworkTopologyStrategy" )
     551             :     {
     552             :         QString datacenters;
     553             :         for( QString key : f_options.keys() )
     554             :         {
     555             :             if( !datacenters.isEmpty() )
     556             :             {
     557             :                 datacenters += ", ";
     558             :             }
     559             :             datacenters += QString("'%1': %2").arg(key).arg(f_options[key]);
     560             :         }
     561             :         //
     562             :         replication_stanza = QString("'class': 'NetworkTopologyStrategy', %1")
     563             :                              .arg(datacenters);
     564             :     }
     565             :     else
     566             :     {
     567             :         std::stringstream ss;
     568             :         ss << "This strategy class, '" << f_private->strategy_class << "', is not currently supported!";
     569             :         throw exception( ss.str().c_str() );
     570             :     }
     571             : 
     572             :     return replication_stanza;
     573             : }
     574             : #endif
     575             : 
     576             : 
     577             : /** \brief This is an internal function used to parse a KsDef structure.
     578             :  *
     579             :  * This function is called internally to parse a KsDef object.
     580             :  *
     581             :  * \param[in] data  The pointer to the KsDef object.
     582             :  *
     583             :  * \sa prepareContextDefinition()
     584             :  */
     585           0 : void context::parseContextDefinition( casswrapper::schema::KeyspaceMeta::pointer_t keyspace_meta )
     586             : {
     587           0 :     f_schema = keyspace_meta;
     588           0 :     for( const auto pair : f_schema->getTables() )
     589             :     {
     590           0 :         table::pointer_t t(getTable(pair.first));
     591           0 :         t->parseTableDefinition(pair.second);
     592             :     }
     593           0 : }
     594             : 
     595             : 
     596             : /** \brief Make this context the current context.
     597             :  *
     598             :  * This function marks this context as the current context where further
     599             :  * function calls will be made (i.e. table and cell editing.)
     600             :  *
     601             :  * Note that whenever you call a function that requires this context to
     602             :  * be current, this function is called automatically. If the context is
     603             :  * already the current context, then no message is sent to the Cassandra
     604             :  * server.
     605             :  *
     606             :  * \sa libdbproxy::setContext()
     607             :  */
     608           0 : void context::makeCurrent()
     609             : {
     610           0 :     parentCassandra()->setCurrentContext( shared_from_this() );
     611           0 : }
     612             : 
     613             : 
     614           0 : QString context::getKeyspaceOptions()
     615             : {
     616           0 :     QString q_str;
     617           0 :     for( const auto& pair : f_schema->getFields() )
     618             :     {
     619           0 :         if( q_str.isEmpty() )
     620             :         {
     621           0 :             q_str = "WITH ";
     622             :         }
     623             :         else
     624             :         {
     625           0 :             q_str += "AND ";
     626             :         }
     627           0 :         q_str += QString("%1 = %2\n")
     628           0 :                 .arg(pair.first)
     629           0 :                 .arg(pair.second.output())
     630             :                 ;
     631             :     }
     632             : 
     633           0 :     return q_str;
     634             : }
     635             : 
     636             : 
     637             : /** \brief Create a new context.
     638             :  *
     639             :  * This function is used to create a new context (keyspace) in the current
     640             :  * Cassandra cluster. Once created, you can make use of it whether it is
     641             :  * attached to the Cassandra cluster or not.
     642             :  *
     643             :  * If you want to include tables in your new context, then create them before
     644             :  * calling this function. It will be faster since you'll end up with one
     645             :  * single request.
     646             :  *
     647             :  * There is an example on how to create a new context with this library:
     648             :  *
     649             :  * \code
     650             :  * libdbproxy::context context("qt_cassandra_test_context");
     651             :  * // default strategy is LocalStrategy which you usually do not want
     652             :  * context.setStrategyClass("org.apache.cassandra.locator.SimpleStrategy");
     653             :  * context.setDurableWrites(true); // by default this is 'true'
     654             :  * context.setReplicationFactor(1); // by default this is undefined
     655             :  * ...  // add tables before calling create() if you also want tables
     656             :  * context.create();
     657             :  * \endcode
     658             :  *
     659             :  * With newer versions of Cassandra (since 1.1) and a network or local
     660             :  * strategy you have to define the replication factors using your data
     661             :  * center names (the "replication_factor" parameter is ignored in that
     662             :  * case):
     663             :  *
     664             :  * \code
     665             :  * context.setDescriptionOption("strategy_class", "org.apache.cassandra.locator.NetworkTopologyStrategy");
     666             :  * context.setDescriptionOption("data_center1", "3");
     667             :  * context.setDescriptionOption("data_center2", "3");
     668             :  * context.setDurableWrites(true);
     669             :  * context.create();
     670             :  * \endcode
     671             :  *
     672             :  * Note that the replication factor is not set by default, yet it is a required
     673             :  * parameter.
     674             :  *
     675             :  * Also, the replication factor can be set to 1, although if you have more
     676             :  * than one node it is probably a poor choice. You probably want a minimum
     677             :  * of 3 for the replication factor, and you probably want a minimum of
     678             :  * 3 nodes in any live cluster.
     679             :  *
     680             :  * \sa table::create()
     681             :  */
     682           0 : void context::create()
     683             : {
     684           0 :     QString q_str( QString("CREATE KEYSPACE IF NOT EXISTS %1").arg(f_context_name) );
     685           0 :     q_str += getKeyspaceOptions();
     686             : 
     687           0 :     order create_keyspace;
     688           0 :     create_keyspace.setCql( q_str, order::type_of_result_t::TYPE_OF_RESULT_SUCCESS );
     689           0 :     create_keyspace.setClearClusterDescription(true);
     690           0 :     order_result const create_keyspace_result(parentCassandra()->getProxy()->sendOrder(create_keyspace));
     691           0 :     if(!create_keyspace_result.succeeded())
     692             :     {
     693           0 :         throw exception("keyspace creation failed");
     694             :     }
     695             : 
     696           0 :     for( auto t : f_tables )
     697             :     {
     698           0 :         t->create();
     699             :     }
     700           0 : }
     701             : 
     702             : /** \brief Update a context with new properties.
     703             :  *
     704             :  * This function defines a new set of properties in the specified context.
     705             :  * In general, the context will be searched in the cluster definitions,
     706             :  * updated in memory then this function called.
     707             :  */
     708           0 : void context::update()
     709             : {
     710           0 :     QString q_str( QString("ALTER KEYSPACE %1").arg(f_context_name) );
     711           0 :     q_str += getKeyspaceOptions();
     712             : 
     713           0 :     order alter_keyspace;
     714           0 :     alter_keyspace.setCql( q_str, order::type_of_result_t::TYPE_OF_RESULT_SUCCESS );
     715           0 :     alter_keyspace.setClearClusterDescription(true);
     716           0 :     order_result const alter_keyspace_result(parentCassandra()->getProxy()->sendOrder(alter_keyspace));
     717           0 :     if(!alter_keyspace_result.succeeded())
     718             :     {
     719           0 :         throw exception("keyspace creation failed");
     720             :     }
     721           0 : }
     722             : 
     723             : 
     724             : /** \brief Drop this context.
     725             :  *
     726             :  * This function drops this context in the Cassandra database.
     727             :  *
     728             :  * Note that contexts are dropped by name so we really only use the name of
     729             :  * the context in this case.
     730             :  *
     731             :  * The context object is still valid afterward, although, obviously
     732             :  * no data can be read from or written to the Cassandra server since the
     733             :  * context is gone from the cluster.
     734             :  *
     735             :  * You may change the parameters of the context and call create() to create
     736             :  * a new context with the same name.
     737             :  *
     738             :  * \warning
     739             :  * If the context does not exist in Cassandra, this function call
     740             :  * raises an exception in newer versions of the Cassandra system
     741             :  * (in version 0.8 it would just return silently.) You may want to
     742             :  * call the libdbproxy::findContext() function first to know whether
     743             :  * the context exists before calling this function.
     744             :  *
     745             :  * \sa libdbproxy::dropContext()
     746             :  * \sa libdbproxy::findContext()
     747             :  */
     748           0 : void context::drop()
     749             : {
     750           0 :     QString q_str(QString("DROP KEYSPACE IF EXISTS %1").arg(f_context_name));
     751             : 
     752           0 :     order drop_keyspace;
     753           0 :     drop_keyspace.setCql( q_str, order::type_of_result_t::TYPE_OF_RESULT_SUCCESS );
     754           0 :     drop_keyspace.setClearClusterDescription(true);
     755           0 :     order_result const drop_keyspace_result(parentCassandra()->getProxy()->sendOrder(drop_keyspace));
     756           0 :     if(!drop_keyspace_result.succeeded())
     757             :     {
     758           0 :         throw exception("drop keyspace failed");
     759             :     }
     760             : 
     761           0 :     resetSchema();
     762           0 :     f_tables.clear();
     763           0 : }
     764             : 
     765             : 
     766             : /** \brief Drop the specified table from the Cassandra database.
     767             :  *
     768             :  * This function sends a message to the Cassandra server so the named table
     769             :  * gets droped from it.
     770             :  *
     771             :  * The function also deletes the table from memory (which means all its
     772             :  * rows and cells are also deleted.) Do not use the table after this call,
     773             :  * even if you kept a shared pointer to it. You may create a new one
     774             :  * with the same name though.
     775             :  *
     776             :  * Note that tables get dropped immediately from the Cassandra database
     777             :  * (contrary to rows).
     778             :  *
     779             :  * \param[in] table_name  The name of the table to drop.
     780             :  */
     781           0 : void context::dropTable(const QString& table_name)
     782             : {
     783           0 :     if(f_tables.find(table_name) == f_tables.end())
     784             :     {
     785           0 :         return;
     786             :     }
     787             : 
     788             :     // keep a shared pointer on the table
     789           0 :     table::pointer_t t(getTable(table_name));
     790             : 
     791             :     // remove from the Cassandra database
     792           0 :     makeCurrent();
     793             : 
     794           0 :     QString q_str(QString("DROP TABLE IF EXISTS %1.%2").arg(f_context_name).arg(table_name));
     795             : 
     796           0 :     order drop_table;
     797           0 :     drop_table.setCql( q_str, order::type_of_result_t::TYPE_OF_RESULT_SUCCESS );
     798           0 :     drop_table.setTimeout(5 * 60 * 1000);
     799           0 :     drop_table.setClearClusterDescription(true);
     800           0 :     order_result const drop_table_result(parentCassandra()->getProxy()->sendOrder(drop_table));
     801           0 :     if(!drop_table_result.succeeded())
     802             :     {
     803           0 :         throw exception("drop table failed");
     804             :     }
     805             : 
     806             :     // disconnect all the cached data from this table
     807           0 :     f_tables.remove(table_name);
     808             : }
     809             : 
     810             : 
     811             : /** \brief Clear the context cache.
     812             :  *
     813             :  * This function clears the context cache. This means all the tables, their
     814             :  * rows, and the cells of those rows all get cleared. None of these can be
     815             :  * used after this call even if you kept a shared pointer to any of these
     816             :  * objects.
     817             :  */
     818           0 : void context::clearCache()
     819             : {
     820           0 :     f_tables.clear();
     821           0 :     parentCassandra()->retrieveContextMeta( shared_from_this(), f_context_name );
     822           0 : }
     823             : 
     824             : 
     825             : /** \brief Get the pointer to the parent object.
     826             :  *
     827             :  * \return Shared pointer to the cassandra object.
     828             :  */
     829           0 : libdbproxy::pointer_t context::parentCassandra() const
     830             : {
     831           0 :     libdbproxy::pointer_t cassandra(f_cassandra.lock());
     832           0 :     if(cassandra == nullptr)
     833             :     {
     834           0 :         throw exception("this context was dropped and is not attached to a cassandra cluster anymore");
     835             :     }
     836             : 
     837           0 :     return cassandra;
     838             : }
     839             : 
     840             : 
     841           6 : } // namespace libdbproxy
     842             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13