/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /***************************************************************************** * Name: NdbEventOperation.hpp * Include: * Link: * Author: Tomas Ulin MySQL AB * Date: 2003-11-21 * Version: 0.1 * Description: Event support * Documentation: * Adjust: 2003-11-21 Tomas Ulin First version. * Adjust: 2003-12-11 Tomas Ulin Alpha Release. ****************************************************************************/ #ifndef NdbEventOperation_H #define NdbEventOperation_H class NdbGlobalEventBuffer; class NdbEventOperationImpl; /** * @class NdbEventOperation * @brief Class of operations for getting change events from database. * * An NdbEventOperation object is instantiated by * NdbEventOperation *Ndb::createEventOperation(const char *eventName, * int bufferLength) * * Prior to that an event must have been created in the Database through * int NdbDictionary::createEvent(NdbDictionary::Event) * * bufferLength indicates size of circular buffer to store event info as * they occur. * * The instance is removed by Ndb::dropEventOperation(NdbEventOperation*) * * For more info see: * ndbapi_example5.cpp * Ndb.hpp * NdbDictionary.hpp * * Known limitations: * * Maximum number of active NdbEventOperations are now set at compile time. * Today 100. This will become a configuration parameter later. * * Maximum number of NdbEventOperations tied to same event are maximum 16 * per process. * * Known issues: * * When several NdbEventOperation s are tied to the same event in the same * process they will share the circular buffer. The BufferLength will then * be the same for all and decided by the first NdbEventOperation * instantiation. Just make sure to instantiate the "largest" one first. * * Today all events INSERT/DELETE/UPDATE and all changed attributes are * sent to the API, even if only specific attributes have been specified. * These are however hidden from the user and only relevant data is shown * after next(). However false exits from pollEvents() may occur and thus * the subsequent next() will return zero, since there was no available * data. Just do pollEvents() again. Will be fixed in later versions. * * Event code does not check table schema version. Make sure to drop events * after table is dropped. Will be fixed in later * versions. * * On a replicated system one will receive each event 2 times, one for each * replica. If a node fails events will not be received twice anymore * for data in corresponding fragment. Will be optimized in later versions. * * If a nodefailiure has occured not all events will be recieved * anymore. Drop NdbEventOperation and Create again after nodes are up * again. Will be fixed in later versions. * * Test status: * Tests have been run on 1-node and 2-node systems * * Known bugs: * * None, except if we can call some of the "isses" above bugs * * Useful API programs: * * select_all -d sys 'NDB$EVENTS_0' * Will show contents in the system table containing created events. * */ class NdbEventOperation { public: enum State {CREATED,EXECUTING,ERROR}; State getState(); /** * Activates the NdbEventOperation to start receiving events. The * changed attribute values may be retrieved after next() has returned * a value greater than zero. The getValue() methods below must be called * prior to execute(). * * @return 0 if successful otherwise -1. */ int execute(); // about the event operation // getting data // NdbResultSet* getResultSet(); /** * Defines a retrieval operation of an attribute value. * The NDB API allocate memory for the NdbRecAttr object that * will hold the returned attribute value. * * @note Note that it is the applications responsibility * to allocate enough memory for aValue (if non-NULL). * The buffer aValue supplied by the application must be * aligned appropriately. The buffer is used directly * (avoiding a copy penalty) only if it is aligned on a * 4-byte boundary and the attribute size in bytes * (i.e. NdbRecAttr::attrSize times NdbRecAttr::arraySize is * a multiple of 4). * * @note There are two versions, NdbOperation::getValue and * NdbOperation::getPreValue for retrieving the current and * previous value repectively. * * @note This method does not fetch the attribute value from * the database! The NdbRecAttr object returned by this method * is not readable/printable before the * NdbEventConnection::execute has been made and * NdbEventConnection::next has returned a value greater than * zero. If a specific attribute has not changed the corresponding * NdbRecAttr will be in state UNDEFINED. This is checked by * NdbRecAttr::isNull which then returns -1. * * @param anAttrName Attribute name * @param aValue If this is non-NULL, then the attribute value * will be returned in this parameter.
* If NULL, then the attribute value will only * be stored in the returned NdbRecAttr object. * @return An NdbRecAttr object to hold the value of * the attribute, or a NULL pointer * (indicating error). */ NdbRecAttr *getValue(const char *anAttrName, char *aValue = 0); NdbRecAttr *getPreValue(const char *anAttrName, char *aValue = 0); /** * Retrieves event resultset if available, inserted into the NdbRecAttrs * specified in getValue() and getPreValue(). To avoid polling for * a resultset, one can use Ndb::pollEvents(int millisecond_timeout) * which will wait on a mutex until an event occurs or the specified * timeout occurs. * * @return >=0 if successful otherwise -1. Return value inicates number * of available events. By sending pOverRun one may query for buffer * overflow and *pOverRun will indicate the number of events that have * overwritten. */ int next(int *pOverRun=0); /** * In the current implementation a nodefailiure may cause loss of events, * in which case isConsistent() will return false */ bool isConsistent(); /** * Query for occured event type. * NdbDictionary::Event::{TE_INSERT,TE_UPDATE,TE_DELETE} * Only valid after next() has returned value >= 0 */ NdbDictionary::Event::TableEvent getEventType(); Uint32 getGCI(); Uint32 getLatestGCI(); void print(); private: friend class NdbEventOperationImpl; friend class Ndb; NdbEventOperation(Ndb *theNdb, const char* eventName,int bufferLength); ~NdbEventOperation(); static int wait(void *p, int aMillisecondNumber); class NdbEventOperationImpl &m_impl; NdbEventOperation(NdbEventOperationImpl& impl); }; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); #endif