/* Copyright (C) 2003-2007 MySQL AB, 2009, 2010 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. 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; version 2 of the License. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef NdbEventOperation_H #define NdbEventOperation_H class NdbGlobalEventBuffer; class NdbEventOperationImpl; /** * @class NdbEventOperation * @brief Class of operations for getting change events from database. * * Brief description on how to work with events: * * - An event, represented by an NdbDictionary::Event, i created in the * Database through * NdbDictionary::Dictionary::createEvent() (note that this can be done * by any application or thread and not necessarily by the "listener") * - To listen to events, an NdbEventOperation object is instantiated by * Ndb::createEventOperation() * - execute() starts the event flow. Use Ndb::pollEvents() to wait * for an event to occur. Use Ndb::nextEvent() to iterate * through the events that have occured. * - The instance is removed by Ndb::dropEventOperation() * * For more info see: * @ref ndbapi_event.cpp * * 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 Ndb::nextEvent(). * - "False" exits from Ndb::pollEvents() may occur and thus * the subsequent Ndb::nextEvent() will return NULL, * since there was no available data. Just do Ndb::pollEvents() again. * - Event code does not check table schema version. Make sure to drop events * after table is dropped. Will be fixed in later * versions. * - If a node failure 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 * * Useful API programs: * * - ndb_select_all -d sys 'NDB$EVENTS_0' * shows contents in the system table containing created events. * * @note this is an inteface to viewing events that is subject to change */ class NdbEventOperation { public: /** * State of the NdbEventOperation object */ enum State { EO_CREATED, ///< Created but execute() not called EO_EXECUTING, ///< execute() called EO_DROPPED, ///< Waiting to be deleted, Object unusable. EO_ERROR ///< An error has occurred. Object unusable. }; /** * Retrieve current state of the NdbEventOperation object */ State getState(); /** * See NdbDictionary::Event. Default is false. */ void mergeEvents(bool flag); /** * Activates the NdbEventOperation to start receiving events. The * changed attribute values may be retrieved after Ndb::nextEvent() * has returned not NULL. The getValue() methods must be called * prior to execute(). * * @return 0 if successful otherwise -1. */ int execute(); /** * 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, getValue() and * 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 * execute() has been made and * Ndb::nextEvent() has returned not NULL. * 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); /** * See getValue(). */ NdbRecAttr *getPreValue(const char *anAttrName, char *aValue = 0); /** * These methods replace getValue/getPreValue for blobs. Each * method creates a blob handle NdbBlob. The handle supports only * read operations. See NdbBlob. */ NdbBlob* getBlobHandle(const char *anAttrName); NdbBlob* getPreBlobHandle(const char *anAttrName); int isOverrun() const; /** * In the current implementation a nodefailiure may cause loss of events, * in which case isConsistent() will return false */ bool isConsistent() const; /** * Query for occured event type. * * @note Only valid after Ndb::nextEvent() has been called and * returned a not NULL value * * @return type of event */ NdbDictionary::Event::TableEvent getEventType() const; /** * Check if table name has changed, for event TE_ALTER */ bool tableNameChanged() const; /** * Check if table frm has changed, for event TE_ALTER */ bool tableFrmChanged() const; /** * Check if table fragmentation has changed, for event TE_ALTER */ bool tableFragmentationChanged() const; /** * Check if table range partition list name has changed, for event TE_ALTER */ bool tableRangeListChanged() const; /** * Retrieve the GCI of the latest retrieved event * * @return GCI number */ Uint64 getGCI() const; /** * Retrieve the AnyValue of the latest retrieved event * * @return AnyValue */ Uint32 getAnyValue() const; /** * Retrieve the complete GCI in the cluster (not necessarily * associated with an event) * * @return GCI number */ Uint64 getLatestGCI() const; /** * Retrieve the TransId of the latest retrieved event * * Only valid for data events. If the kernel does not * support transaction ids with events, the max Uint64 * value is returned. * * @return TransId */ Uint64 getTransId() const; /** * Get the latest error * * @return Error object. */ const struct NdbError & getNdbError() const; #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** these are subject to change at any time */ const NdbDictionary::Table* getTable() const; const NdbDictionary::Event *getEvent() const; const NdbRecAttr *getFirstPkAttr() const; const NdbRecAttr *getFirstPkPreAttr() const; const NdbRecAttr *getFirstDataAttr() const; const NdbRecAttr *getFirstDataPreAttr() const; // bool validateTable(NdbDictionary::Table &table) const; void setCustomData(void * data); void * getCustomData() const; void clearError(); int hasError() const; int getReqNodeId() const; int getNdbdNodeId() const; #endif #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /* * */ void print(); #endif private: #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL friend class NdbEventOperationImpl; friend class NdbEventBuffer; #endif NdbEventOperation(Ndb *theNdb, const char* eventName); ~NdbEventOperation(); class NdbEventOperationImpl &m_impl; NdbEventOperation(NdbEventOperationImpl& impl); NdbEventOperation(const NdbEventOperation&); // Not impl. NdbEventOperation&operator=(const NdbEventOperation&); }; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); #endif