My Project
rpl_injector.h
00001 /* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #ifndef INJECTOR_H
00017 #define INJECTOR_H
00018 
00019 /* Pull in 'byte', 'my_off_t', and 'uint32' */
00020 #include <my_global.h>
00021 #include <my_bitmap.h>
00022 
00023 #include "rpl_constants.h"
00024 #include "table.h"                              /* TABLE */
00025 
00026 /* Forward declarations */
00027 class handler;
00028 class MYSQL_BIN_LOG;
00029 struct TABLE;
00030 
00031 
00032 /*
00033   Injector to inject rows into the MySQL server.
00034   
00035   The injector class is used to notify the MySQL server of new rows that have
00036   appeared outside of MySQL control.
00037  
00038   The original purpose of this is to allow clusters---which handle replication
00039   inside the cluster through other means---to insert new rows into binary log.
00040   Note, however, that the injector should be used whenever rows are altered in
00041   any manner that is outside of MySQL server visibility and which therefore
00042   are not seen by the MySQL server.
00043  */
00044 class injector 
00045 {
00046 public:
00047 
00048   /*
00049     Get an instance of the injector.
00050 
00051     DESCRIPTION
00052       The injector is a Singleton, so this static function return the
00053       available instance of the injector.
00054 
00055     RETURN VALUE
00056       A pointer to the available injector object.
00057   */
00058   static injector *instance();
00059 
00060   /*
00061     Delete the singleton instance (if allocated). Used during server shutdown.
00062   */
00063   static void free_instance();
00064 
00065     /*
00066       A transaction where rows can be added.
00067 
00068       DESCRIPTION
00069         The transaction class satisfy the **CopyConstructible** and
00070         **Assignable** requirements.  Note that the transaction is *not*
00071         default constructible.
00072      */
00073     class transaction {
00074       friend class injector;
00075     public:
00076       /* Convenience definitions */
00077       typedef uchar* record_type;
00078       typedef uint32 server_id_type;
00079 
00080       /*
00081         Table reference.
00082 
00083         RESPONSIBILITY
00084 
00085           The class contains constructors to handle several forms of
00086           references to tables.  The constructors can implicitly be used to
00087           construct references from, e.g., strings containing table names.
00088 
00089         EXAMPLE
00090 
00091           The class is intended to be used *by value*.  Please, do not try to
00092           construct objects of this type using 'new'; instead construct an
00093           object, possibly a temporary object.  For example:
00094 
00095             injector::transaction::table tbl(share->table, true);
00096             MY_BITMAP cols;
00097             bitmap_init(&cols, NULL, (i + 7) / 8, false);
00098             inj->write_row(::server_id, tbl, &cols, row_data);
00099 
00100           or
00101 
00102             MY_BITMAP cols;
00103             bitmap_init(&cols, NULL, (i + 7) / 8, false);
00104             inj->write_row(::server_id, 
00105                            injector::transaction::table(share->table, true), 
00106                            &cols, row_data);
00107 
00108           This will work, be more efficient, and have greater chance of
00109           inlining, not run the risk of losing pointers.
00110 
00111         COLLABORATION
00112 
00113           injector::transaction
00114             Provide a flexible interface to the representation of tables.
00115 
00116       */
00117       class table 
00118       {
00119       public:
00120         class save_sets {
00121         public:
00122           save_sets(table const &tbl, MY_BITMAP const *new_rs, MY_BITMAP const *new_ws)
00123             : m_table(tbl.get_table()),
00124               save_read_set(m_table->read_set),
00125               save_write_set(m_table->write_set)
00126           {
00127             m_table->column_bitmaps_set_no_signal(const_cast<MY_BITMAP*>(new_rs),
00128                                                   const_cast<MY_BITMAP*>(new_ws));
00129           }
00130 
00131           ~save_sets() {
00132             m_table->column_bitmaps_set_no_signal(save_read_set, save_write_set);
00133           }
00134 
00135         private:
00136           TABLE *m_table;
00137           MY_BITMAP *save_read_set;
00138           MY_BITMAP *save_write_set;
00139         };
00140 
00141         table(TABLE *table, bool is_transactional) 
00142             : m_table(table), m_is_transactional(is_transactional)
00143         { 
00144         }
00145 
00146         char const *db_name() const { return m_table->s->db.str; }
00147         char const *table_name() const { return m_table->s->table_name.str; }
00148         TABLE *get_table() const { return m_table; }
00149         bool is_transactional() const { return m_is_transactional; }
00150 
00151       private:
00152         TABLE *m_table;
00153         bool m_is_transactional;
00154       };
00155 
00156       /*
00157         Binlog position as a structure.
00158       */
00159       class binlog_pos {
00160         friend class transaction;
00161       public:
00162         char const *file_name() const { return m_file_name; }
00163         my_off_t file_pos() const { return m_file_pos; }
00164 
00165       private:
00166         char const *m_file_name;
00167         my_off_t m_file_pos;
00168       };
00169 
00170       transaction() : m_thd(NULL) { }
00171       transaction(transaction const&);
00172       ~transaction();
00173 
00174       /* Clear transaction, i.e., make calls to 'good()' return false. */
00175       void clear() { m_thd= NULL; }
00176 
00177       /* Is the transaction in a good state? */
00178       bool good() const { return m_thd != NULL; }
00179 
00180       /* Default assignment operator: standard implementation */
00181       transaction& operator=(transaction t) {
00182         swap(t);
00183         return *this;
00184       }
00185       
00186       /*
00187 
00188         DESCRIPTION
00189 
00190           Register table for use within the transaction.  All tables
00191           that are going to be used need to be registered before being
00192           used below.  The member function will fail with an error if
00193           use_table() is called after any *_row() function has been
00194           called for the transaction.
00195 
00196         RETURN VALUE
00197 
00198           0         All OK
00199           >0        Failure
00200 
00201        */
00202       int use_table(server_id_type sid, table tbl);
00203 
00204       /*
00205         Add a 'write row' entry to the transaction.
00206       */
00207       int write_row (server_id_type sid, table tbl, 
00208                      MY_BITMAP const *cols, size_t colcnt,
00209                      record_type record,
00210                      const uchar* extra_row_info);
00211       int write_row (server_id_type sid, table tbl,
00212                       MY_BITMAP const *cols, size_t colcnt,
00213                       record_type record);
00214 
00215       /*
00216         Add a 'delete row' entry to the transaction.
00217       */
00218       int delete_row(server_id_type sid, table tbl, 
00219                      MY_BITMAP const *cols, size_t colcnt,
00220                      record_type record,
00221                      const uchar* extra_row_info);
00222       int delete_row(server_id_type sid, table tbl,
00223                      MY_BITMAP const *cols, size_t colcnt,
00224                      record_type record);
00225       /*
00226         Add an 'update row' entry to the transaction.
00227       */
00228       int update_row(server_id_type sid, table tbl, 
00229                      MY_BITMAP const *cols, size_t colcnt,
00230                      record_type before, record_type after,
00231                      const uchar* extra_row_info);
00232       int update_row(server_id_type sid, table tbl,
00233                      MY_BITMAP const *cols, size_t colcnt,
00234                      record_type before, record_type after);
00235 
00236       /*
00237         Commit a transaction.
00238 
00239         This member function will clean up after a sequence of *_row calls by,
00240         for example, releasing resource and unlocking files.
00241       */
00242       int commit();
00243 
00244       /*
00245         Rollback a transaction.
00246 
00247         This member function will clean up after a sequence of *_row calls by,
00248         for example, releasing resource and unlocking files.
00249       */
00250       int rollback();
00251 
00252       /*
00253         Get the position for the start of the transaction.
00254 
00255         This is the current 'tail of Binlog' at the time the transaction
00256         was started.  The first event recorded by the transaction may
00257         be at this, or some subsequent position.  The first event recorded
00258         by the transaction will not be before this position.
00259       */
00260       binlog_pos start_pos() const;
00261 
00262       /*
00263         Get the next position after the end of the transaction
00264 
00265         This call is only valid after a transaction has been committed.
00266         It returns the next Binlog position after the committed transaction.
00267         It is guaranteed that no other events will be recorded between the
00268         COMMIT event of the Binlog transaction, and this position.
00269         Note that this position may be in a different log file to the COMMIT
00270         event.
00271 
00272         If the commit had an error, or the transaction was empty and nothing
00273         was binlogged then the next_pos will have a NULL file_name(), and
00274         0 file_pos().
00275 
00276       */
00277       binlog_pos next_pos() const;
00278 
00279     private:
00280       /* Only the injector may construct these object */
00281       transaction(MYSQL_BIN_LOG *, THD *);
00282 
00283       void swap(transaction& o) {
00284         /* std::swap(m_start_pos, o.m_start_pos); */
00285         {
00286           binlog_pos const tmp= m_start_pos;
00287           m_start_pos= o.m_start_pos;
00288           o.m_start_pos= tmp;
00289         }
00290 
00291         /* std::swap(m_end_pos, o.m_end_pos); */
00292         {
00293           binlog_pos const tmp= m_next_pos;
00294           m_next_pos= o.m_next_pos;
00295           o.m_next_pos= tmp;
00296         }
00297 
00298         /* std::swap(m_thd, o.m_thd); */
00299         {
00300           THD* const tmp= m_thd;
00301           m_thd= o.m_thd;
00302           o.m_thd= tmp;
00303         }
00304         {
00305           enum_state const tmp= m_state;
00306           m_state= o.m_state;
00307           o.m_state= tmp;
00308         }
00309       }
00310 
00311       enum enum_state
00312       {
00313         START_STATE,                            /* Start state */
00314         TABLE_STATE,      /* At least one table has been registered */
00315         ROW_STATE,          /* At least one row has been registered */
00316         STATE_COUNT               /* State count and sink state */
00317       } m_state;
00318 
00319       /*
00320         Check and update the state.
00321 
00322         PARAMETER(S)
00323 
00324           target_state
00325               The state we are moving to: TABLE_STATE if we are
00326               writing a table and ROW_STATE if we are writing a row.
00327 
00328         DESCRIPTION
00329 
00330           The internal state will be updated to the target state if
00331           and only if it is a legal move.  The only legal moves are:
00332 
00333               START_STATE -> START_STATE
00334               START_STATE -> TABLE_STATE
00335               TABLE_STATE -> TABLE_STATE
00336               TABLE_STATE -> ROW_STATE
00337 
00338           That is:
00339           - It is not possible to write any row before having written at
00340             least one table
00341           - It is not possible to write a table after at least one row
00342             has been written
00343 
00344         RETURN VALUE
00345 
00346            0    All OK
00347           -1    Incorrect call sequence
00348        */
00349       int check_state(enum_state const target_state)
00350       {
00351 #ifndef DBUG_OFF
00352         static char const *state_name[] = {
00353           "START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT"
00354         };
00355 
00356         DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT);
00357         DBUG_PRINT("info", ("In state %s", state_name[m_state]));
00358 #endif
00359 
00360         if (m_state <= target_state && target_state <= m_state + 1 &&
00361             m_state < STATE_COUNT)
00362           m_state= target_state;
00363         else
00364           m_state= STATE_COUNT;
00365         return m_state == STATE_COUNT ? 1 : 0;
00366       }
00367 
00368 
00369       binlog_pos m_start_pos;
00370       binlog_pos m_next_pos;
00371       THD *m_thd;
00372     };
00373 
00374     /*
00375        Create a new transaction.  This member function will prepare for a
00376        sequence of *_row calls by, for example, reserving resources and
00377        locking files. The call uses placement semantics and will overwrite
00378        the transaction.
00379 
00380          injector::transaction trans2;
00381          inj->new_trans(thd, &trans);
00382      */
00383     void new_trans(THD *, transaction *);
00384 
00385     int record_incident(THD*, Incident incident);
00386     int record_incident(THD*, Incident incident, LEX_STRING const message);
00387 
00388 private:
00389     explicit injector();
00390     ~injector() { }             /* Nothing needs to be done */
00391     injector(injector const&);  /* You're not allowed to copy injector
00392                                    instances.
00393                                 */ 
00394 };
00395 
00396 #endif /* INJECTOR_H */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines