¹ÙÀ̳ʸ® ·Î±× API¿Í ¸®Çø®ÄÉÀÌ¼Ç ¸®½º³Ê
ÀÌ ºí·Î±×´Â MySQL ¸®Çø®ÄÉÀÌ¼Ç ¸®½º³Ê ÆÐŰÁö¿¡ ÀÖ´Â ¹ÙÀ̳ʸ® ·Î±× API¿¡ ´ëÇÑ °ÍÀÔ´Ï´Ù. ¹ÙÀ̳ʸ® ·Î±× API¿Í ¸®Çø®ÄÉÀÌ¼Ç ¸®½º³Ê°¡ MySQL µ¥ÀÌÅͺ£À̽ºÀÇ Á÷°üÀûÀÎ °Ë»ö°ú ¹«½¼ »ó°üÀÌ ÀÖ´ÂÁö ÀǾÆÇմϱî? Change-Data-Capture(CDC)¶ó°í ºÒ¸®´Â ±â¼úÀ» ÀÌ¿ëÇÏ¿©, ¾î¶² ¿ÜºÎÀ妽º¿¡ ¾÷µ¥ÀÌÆ®¸¦ ÇÒ ¶§, ´ç½ÅÀº ¹ÙÀ̳ʸ® ·Î±×¸¦ »ç¿ëÇÒ ¼ö Àֱ⠶§¹®ÀÔ´Ï´Ù.
ÀÌ ºí·Î±×¸¦ Àаí ÀÖ´Â µ¶ÀÚ°¡ Àý´ë·Î Ãʺ¸ÀÚ°¡ ¾Æ´Ï¶ó°í °¡Á¤ÇÕ´Ï´Ù. MySQL ¸®Çø®ÄÉÀ̼ǿ¡ ´ëÇÏ¿© ÀÌÇØÇϰí, ¾à°£ÀÇ C++¿¡ ´ëÇÑ Áö½ÄÀÌ ÇÊ¿äÇÕ´Ï´Ù.
´ÙÀ½ µ¿¿µ»óÀ» º¸¸é, ¹ÙÀ̳ʸ® ·Î±× APIÀÇ ¹Ýº¹ÀûÀÎ ¾÷µ¥ÀÌÆ®¸¦ »ç¿ëÇÏ¿© MySQLÀÇ Å×ÀÌºí¿¡ Å×½ºÆ® Çʵ带 ãÀ» ¼ö ÀÖ´Â ÀαâÀÖ´Â ¿£ÅÍÇÁ¶óÀÌÁî °Ë»ö ÇÁ·Î±×·¥ÀÎ 'SOLR'·Î ¸¸µé¾îÁø °£´ÜÇÑ ÀÀ¿ëÇÁ·Î±×·¥ÀÇ °³³äÀ» º¸¿©ÁÙ °ÍÀÔ´Ï´Ù.
µ¿¿µ»óÀÇ ¿¹Á¦´Â Çà±â¹ÝÀÇ º¹Á¦(¸®Çø®ÄÉÀ̼Ç) À̺¥Æ®¸¦ »ç¿ëÇÕ´Ï´Ù. Çà±â¹Ý º¹Á¦´Â ÀϹÝÀûÀ¸·Î Ưº°ÇÑ ¿ëµµÀÇ µ¥ÀÌÅÍ ÀúÀå°ú ÇÔ²² MySQLÀ» ÅëÇÕÇϴ°ÍÀ» ½±°Ô ¸¸µé¾îÁÝ´Ï´Ù. ³ª´Â ¹ÙÀ̳ʸ® ·Î±×ÀÇ À̺¥Æ®°¡ ¹ß»ýÇÒ ¶§, ĸÃÄÇÏ°í ºÐ¼®ÇÏ´Â °ÍÀÌ ½±°Ô ¹ÙÀ̳ʸ® ·Î±× API·Î Á¢¸ñµÉ ¼ö ÀÖ´Ù°í »ý°¢Çß½À´Ï´Ù. ¾ÆÁ÷ ´õ Áö¿øÇؾßÇϰí, º¹Á¦ ¹× µ¥ÀÌÅÍ ÅëÇÕÀÇ »ç¿ë »ç·Ê´Â ¸¹Áö¸¸ ¾Æ¸¶µµ ¾ÆÁ÷ À̰ÍÀÌ ¹Ù¸¥ 뱡ÇâÀ» ã¾Æ°¡±â¿¡´Â À̸¥ ´Ü°èÀÏ ¼ö ÀÖ½À´Ï´Ù.
ÀüÁ¦Á¶°Ç
µ¥¸ð¸¦ º¹»çÇϱâ Àü¿¡, ½Ã½ºÅÛ ±¸¼ºÀ» ¾Ë¾Æ º¾½Ã´Ù.
- ÃֽЏ®Çø®ÄÉÀÌ¼Ç ¸®½º³Ê¸¦ º¹»çÇÕ´Ï´Ù. MySQL Labs ¶Ç´Â º¹Á¦ ¼Ò½º·Î ºÎÅÍ ¹ÙÀ̳ʸ® ÆÄÀÏÀ» ´Ù¿î·Îµå ÇÕ´Ï´Ù.
- ÃֽŠg++ (4.4 /4.5°¡ ÁÁ½À´Ï´Ù.)¿Í Boost 1.45 ¶Ç´Â ±× ÀÌ»ó ¹öÀü
- OpenSSL
- Cmake
- Netbeans (¼±ÅûçÇ×)
- Clucence
- SOLR
- Linux (¼±ÅûçÇ×)
- MySQL 5.6
- ´ë´ãÇÑ ÇØÄ¿ÀÇ ¸¶À½°¡Áü!
±âº» ¿¹Á¦
binlog API¸¦ »ç¿ëÇÏ·Á¸é Çì´õÆÄÀÏ¿¡ "binlog_api.h"¿Í, "libreplication" ¶óÀ̺귯¸®ÀÇ ¸µÅ©¸¦ Æ÷ÇÔÇØ¾ß ÇÕ´Ï´Ù.
API´Â ³×Æ®¿öÅ© ¶Ç´Â ÆÄÀÏ ½Ã½ºÅÛ ÅëÇØ¼ ¹ÙÀ̳ʸ® ·Î±×¿¡ ¿¬°áÇÕ´Ï´Ù. CDCÀÇ ±¸ÇöÀ» À§Çؼ, ³×Æ®¿öÅ©¸¦ ÅëÇØ¼ ¼¹ö¿¡ Á÷Á¢¿¬°áÇϸé, Á¤Àû ÆÄÀÏÀ» Àд °Íº¸´Ù ÈξÀ ´õ Àç¹ÌÀÖ´Â °ÍÀÌ µÇµµ·Ï ½ÃÀÛÇÒ ¼ö ÀÖ½À´Ï´Ù.
¾Æ·¡ ¿¹Á¦´Â ´Ü¼øÈ÷ ÁöÁ¤µÈ À§Ä¡¿¡¼ ¹ÙÀ̳ʸ® ·Î±×¿¡ ¿¬°áÇÏ´Â ÇÁ·Î±×·¥ À强 ¹æ¹ýÀ» º¸¿©ÁÝ´Ï´Ù.
/* example1.cpp */
#include
#include "binlog_api.h"
int main(int argc, char** argv){
if (argc != 2) {
fprintf(stderr,"Usage:\n\treplaybinlog URL\n\nExample:\n\treplaybinlog mysql://root:mypasswd@127.0.0.1:3306\n\n");
return (EXIT_FAILURE);
}
Binary_log binlog(system::create_transport(argv[1]));
if (binlog.connect())
{
fprintf(stderr,"Can't connect to the master.\n");
return (EXIT_FAILURE);
}
if (binlog.set_position(4) != ERR_OK)
{
fprintf(stderr,"Can't reposition the binary log reader.\n");
return (EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
ÄÄÆÄÀÏ ÄÚµå »ç¿ë
% g++ example1.cpp -I/path/to/mysql-replication-listener/include/ -L/path/to/mysql-replication-listener/include/ -lreplication -lboost_system -o example1
create_transport() helper ÇÔ¼ö´Â URLÀ» Àμö·Î ÇÏ¿©, Binary_log_driver °´Ã¼¸¦ ¹ÝȯÇÕ´Ï´Ù. À̰ÍÀº ³ªÁß¿¡ ¹ÙÀ̳ʸ® ·Î±×¿¡ ¿¬°áÇÒ ¼ö ÀÖ´Â Binary_log °´Ã¼¿¡¼ »ç¿ëµË´Ï´Ù. ¿Â¶óÀÎ ³×Æ®¿öÅ© ¿¬°áÀ» À§Çؼ "mysql://username:pass@localhost:3365"°ú °°Àº °ÍÀ» ÀÔ·ÂÇϰí, Á¤Àû ÆÄÀÏÀ» ¿¶÷Çϱâ À§Çؼ "file:///tmp/binlog.000001"°ú °°Àº Çü½ÄÀ» ÀÔ·ÂÇÕ´Ï´Ù.
´ÙÀ½À» ÀνÄÇÏ´Â µÎ °¡Áö Áß¿äÇÑ °³³äÀÌ ÀÖ½À´Ï´Ù.
- À̺¥Æ® ·çÇÁ.
- ÄÜÅÙÃ÷ Çڵ鷯 ÆÄÀÌÇÁ¶óÀÎ.
À̺¥Æ® ·çÇÁ´Â ´Ü¼øÈ÷ ÀϹÝÀûÀÎ GUI À̺¥Æ® ·çÇÁ¿Í °°ÀÌ ¸ðµç ÇÁ·Î±×·¡¸Ó¿¡°Ô »ó´çÈ÷ Ç¥ÁØÈ µÇ¾î¾ßÇÕ´Ï´Ù. »õ·Î¿î À̺¥Æ®°¡ °Ô½ÃµÇ¾î ÀÖ´ÂÁö È®ÀÎÇÏ°í ±×°ÍÀ» ½ÇÇàÇÏ¿© À̺¥Æ® ´ë±â¿(Å¥)¿¡¼ ¹Ð¾î³À´Ï´Ù.
¸¸¾à¿¡ ¿À¸¥ÂÊÀ¸·Î ¹Ð¾î³»´Â ÇÔ¼ö°¡ ÀÖ°í ±× ÇÔ¼öÀÌ ½ÇÇàµÇ¾úÀ»¶§, ²ø¾î³»±â(Pulling)´Â Ç×»ó Æí¸®ÇÑ °³¹ß ÆÐÅÏÀ̳ª ´õ ÁÁÀº ¹æ¹ýÀÌ µÉ ¼ö ¾ø½À´Ï´Ù. À̺¥Æ® Áß½ÉÀÇ (¶Ç´Â ºñµ¿±â½Ä) API³ª ÄÜÆ°Ã÷ Çڵ巯 ÆÄÀÌÇÁ¶óÀÎÀÇ ¶óÀ̺귯¸® ¾È¿¡¼ ½ÇÇöµÇ´Â ÇÁ·Î±×·¥ ¹æ¹ý·ÐÀº Á¾Á¾ ¾ð±ÞµË´Ï´Ù.
°¢°¢ÀÇ ÄÜÅÙÃ÷ Çڵ鷯´Â ½ºÅÿ¡ ¹Ð¾î ³Ö°í ÇϳªÀÇ Çڵ鷯°¡ ÀçÀÛ¼º ÇÏ´Â °ÍÀ» °¡´ÉÇÏ°Ô Çϰųª, ¶Ç´Â ½ºÅÿ¡¼ Çڵ鷯¸¦ ó¸® Çϱâ À§ÇØ ÇൿÇÏ´Â »õ·Î¿î À̺¥Æ®¸¦ ¸¸µì´Ï´Ù.
¾Æ·¡ÀÇ µ¿¿µ»ó ¿¹Á¦¿¡¼ Äõ¸® ºÐ¼®À» À§ÇÑ ÄÜÅÙÃ÷ Çڵ鷯 À̺¥Æ®°¡ ½ºÅÿ¡ ¹Ð¾î ³Ö½À´Ï´Ù. ±¸¹® ±â¹Ý º¹Á¦¿¡ ´ëÇÑ Äõ¸®À̺¥Æ®°¡ »ç¿ëµÇ°í, ¼¹ö¿Í ´Ù¸¥°Í »çÀÌ¿¡¼ ½ÇÇàµÈ ½ÃÁ¦±¸¹®ÀÌ ÆäÀ̷ε忡 Æ÷ÇԵǾî ÀÖ½À´Ï´Ù.
´ÙÀ½ ¿¹Á¦¿¡¼´Â SOLR ¿£ÅÍÇÁ¶óÀÌÁî °Ë»ö ¿£Áø¿¡ ´ëÇØ¼ ¾Ë¾Æº¸°Ú½À´Ï´Ù. ¿©±â¼´Â ÀǵµÀûÀ¸·Î ¼¼¼¼ÇÑ ³»¿ëÀ» Á¦¿ÜÇϰÚÁö¸¸, ÁÖ ¸ñÀûÀº APIÀÇ ÀϹÝÀûÀÎ °³³ä°ú ±â´ÉÀ» ½Å¼ÓÇÏ°Ô Á¦°øÇÏ´Â °ÍÀÔ´Ï´Ù.
°í±Þ¿¹Á¦
´ÙÀ½ ¿¹Á¦¿¡¼´Â SOLR ¿£ÅÍÇÁ¶óÀÌÁî °Ë»ö ¿£Áø¿¡ ´ëÇØ¼ ¾Ë¾Æº¸°Ú½À´Ï´Ù.
Çà ±â¹Ý º¹Á¦¿¡ ´ëÇÑ ¿É¼Ç°ú ÇÔ²² MySQL ¼¹ö°¡ ½ÃÀ۵ǰí, clucene ¶óÀ̺귯¸®´Â MySQL ¼¹ö¿¡¼ ½Ç½Ã°£À¸·Î µ¥ÀÌÅ͸¦ ·ç¾À À妽º¿¡ ¾÷µ¥ÀÌÆ® ÇϱâÀ§Çؼ »ç¿ëµË´Ï´Ù.
³ª´Â clucene »ç¿ë¹æ¹ý¿¡ ´ëÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀ» Æ÷ÇÔÇÏÁö´Â ¾ÊÁö¸¸, ¼Ò½º¿¡ °ü½ÉÀÌ ÀÖ´Ù¸é, ÀúÀå¼Ò¿¡ ÀÖ´Â ¿¹Á¦ ÆÄÀÏÀÇ ÀϺθ¦ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
¾Æ·¡ÀÇ ÇÁ·Î±×·¥ ±¸Á¶´Â ¾Õ¿¡¼ ¼³¸íÇÑ ÆÐÅÏÀ» µû¸¨´Ï´Ù: binlog °´Ã¼°¡ ÀÖ°í, À̺¥Æ® ·çÇÁ°¡ ÀÖ°í, ¾î¶² ¼±ÅÂµÈ À̺¥Æ®¿¡ ´ëÇÑ Æ®¸®°Å¸¦ °¡Áø ÄÜÅÙÃ÷ Çڵ鷯°¡ ÀÖ½À´Ï´Ù.
#include <stdlib.h>
#include <boost/foreach.hpp>
#include "binlog_api.h"
#include "table_update.h"
#include "table_delete.h"
#include "table_insert.h"
#include "table_index.h"
using mysql::system::create_transport;
using mysql::Binary_log;
std::string cl_index_file;
class Incident_handler : public mysql::Content_handler
{
public:
Incident_handler() : mysql::Content_handler() {}
Binary_log_event *process_event(mysql::Incident_event *incident)
{
std::cout << "Event type: "
<< mysql::system::get_event_type_str(incident->get_event_type())
<< " length: " << incident->header()->event_length
<< " next pos: " << incident->header()->next_position
<< std::endl;
std::cout << "type= "
<< (unsigned)incident->type
<< " message= "
<< incident->message
<< std::endl
<< std::endl;
/* Consume the event */
delete incident;
return 0;
}
};
class Applier : public mysql::Content_handler
{
public:
Applier(Table_index *index)
{
m_table_index= index;
}
mysql::Binary_log_event *process_event(mysql::Row_event *rev)
{
boost::uint64_t table_id= rev->table_id;
Int2event_map::iterator ti_it= m_table_index->find(table_id);
if (ti_it == m_table_index->end ())
{
std::cout << "Table id "
<< table_id
<< " was not registered by any preceding table map event."
<< std::endl;
return rev;
}
/*
Each row event contains multiple rows and fields. The Row_iterator
allows us to iterate one row at a time.
*/
mysql::Row_event_set rows(rev, ti_it->second);
/*
Create a fuly qualified table name
*/
std::ostringstream os;
os << ti_it->second->db_name << '.' << ti_it->second->table_name;
mysql::Row_event_set::iterator it= rows.begin();
do {
mysql::Row_of_fields fields= *it;
if (rev->get_event_type() == mysql::WRITE_ROWS_EVENT)
table_insert(os.str(),fields);
if (rev->get_event_type() == mysql::UPDATE_ROWS_EVENT)
{
++it;
mysql::Row_of_fields fields2= *it;
table_update(os.str(),fields,fields2);
}
if (rev->get_event_type() == mysql::DELETE_ROWS_EVENT)
table_delete(os.str(),fields);
} while (++it != rows.end());
/* Consume the event */
delete rev;
return 0;
}
private:
Table_index *m_table_index;
};
int main(int argc, char** argv)
{
if (argc != 3)
{
fprintf(stderr,"Usage:\n\nmysql2lucene URL\n\nExample:\n\nmysql2lucene mysql://root@127.0.0.1:3306 myindexfile\n\n");
return (EXIT_FAILURE);
}
Binary_log binlog(create_transport(argv[1]));
cl_index_file.append (argv[2]);
/*
Attach a custom event content handlers
*/
Incident_handler incident_hndlr;
Table_index table_event_hdlr;
Applier replay_hndlr(&table_event_hdlr);
binlog.content_handler_pipeline()->push_back(&table_event_hdlr);
binlog.content_handler_pipeline()->push_back(&incident_hndlr);
binlog.content_handler_pipeline()->push_back(&replay_hndlr);
if (binlog.connect())
{
fprintf(stderr,"Can't connect to the master.\n");
return (EXIT_FAILURE);
}
binlog.set_position("searchbin.000001", 4);
bool quit= false;
while(!quit)
{
/*
Pull events from the master. This is the heart beat of the event listener.
*/
Binary_log_event *event;
binlog.wait_for_next_event(&event);
/*
Print the event
*/
std::cout << "Event type: "
<< mysql::system::get_event_type_str(event->get_event_type())
<< " length: " << event->header()->event_length
<< " next pos: " << event->header()->next_position
<< std::endl;
/*
Perform a special action based on event type
*/
switch(event->header()->type_code)
{
case mysql::QUERY_EVENT:
{
const mysql::Query_event *qev= static_cast(event);
std::cout << "query= "
<< qev->query
<< " db= "
<< qev->db_name
<< std::endl
<< std::endl;
if (qev->query.find("DROP TABLE REPLICATION_LISTENER") != std::string::npos)
{
quit= true;
}
}
break;
case mysql::ROTATE_EVENT:
{
mysql::Rotate_event *rot= static_cast(event);
std::cout << "filename= "
<< rot->binlog_file.c_str()
<< " pos= "
<< rot->binlog_pos
<< std::endl
<< std::endl;
}
break;
} // end switch
delete event;
} // end loop
return (EXIT_SUCCESS);
}
ÀÌ Äڵ带 À¯¿ëÇÏ°Ô »ç¿ëÇÒ·Á¸é, SOLR À¥ ¼ºñ½º¿Í MySQL 5.6¼¹ö¿Í µ¥ÀÌÅͺ£À̽º¿¡ ÀÔ·ÂÀ» °ø±ÞÇÏ´Â ¸î¸î MySQL clientÀ» ½ÇÇàÇØ¾ß ÇÕ´Ï´Ù. ¶ÇÇÑ lucene À妽º¸¦ ÀúÀåÇÒ À§Ä¡¸¦ ÁöÁ¤ÇÏ¾ß ÇÕ´Ï´Ù.
Çà±â¹Ý ¸®Çø®ÄÉÀ̼Ç(--binlog_format=row)°ú "searchbin"°ú °°Àº ¹ÙÀ̳ʸ® ·Î±×ÀÇ ±âº»¸í(--log_bin=searchbin)À» »ç¿ëÇÏ¿© MySQL ¼¹ö¸¦ ½ÇÇàÇÒ ¼ö ÀÖ´ÂÁö È®ÀÎÇØ¾ßÇÕ´Ï´Ù. MySQL 5.6 ¼Ò½ºÄڵ带 ´Ù¿î·Îµå ÇÏ¿´À» °æ¿ì¿¡´Â mysql-test µð·ºÅ丮¿¡ ÀÖ´Â Å×½ºÆ® µµ±¸ÀÎ 'MTR'À» »ç¿ëÇÏ¿© ½±°Ô ¾Ë ¼ö ÀÖ½À´Ï´Ù. ´Ü¼øÇÑ À¯Çü:
% ./mtr --start alias --mysqld=--log_bin=searchbin --mysqld=--binary_log=row
ÄÝ¼Ö ½ÇÇàÁß¿¡¼ SOLR Ç÷§ÆûÀ» ¾òÀ»·Á¸é, SOLR ¸Å´º¾óÀ̳ª ¼Ò½ºÆÐŰÁöÀÇ ¿¹Á¦µð·ºÅ丮¿¡¼ À̰ÍÀ» ½ÇÇàÇÕ´Ï´Ù.
% java -jar start.jar
¶ÇÇÑ clucene À妽ºÀÇ À§Ä¡¸¦ ÁöÁ¤ÇÏ´Â °ÍÀ» ÀÖÁö ¸»¾Æ¾ß ÇÕ´Ï´Ù.
Applier Ŭ·¡½º´Â ¸î°¡Áö Ãß°¡ ¼³¸íÀÌ ÇÊ¿äÇÕ´Ï´Ù. Çà ±â¹ÝÀ¸·Î À̺¥Æ®¸¦ ±¸¹® ºÐ¼®Çϴ ŪÈ÷ ÀÌ ºÎºÐÀÌ´Ù. ±× ¾Æ·¡ ´õ ¸¹Àº °Íµé:
¿ ±â¹Ý À̺¥Æ® ºÐ¼®
¸®Çø®ÄÉÀÌ¼Ç ½ºÆ®¸²À¸·Î ºÎÅÍ µ¥ÀÌÅ͸¦ ¹Þ¾Æ¿Ã ¶§, µ¥À̺í À̸§, Çõå Çü½Ä ¹× À¯¿ëÇÑ ÇüÅ×ÀÇ ½ÇÁ¦ µ¥ÀÌÅÍ¿Í °°Àº °ÍµéÀº ¾î¶»°Ô ÃàÃâÇմϱî?
¹ÙÀ̳ʸ® ·Î±× ÇÁ·ÎÅäÄÝ¿¡ ´ëÇÑ ¼³¸íÀº MySQL forge¿¡ À§Ä¡Çϰí ÀÖ½À´Ï´Ù. ¼¼ºÎ»çÇ׿¡ ´ëÇÏ¿© ÀÚ¼¼È÷ ¾Ë°í ½Í´Ù¸é, MySQL forge´Â Á¤º¸ÀÇ ¿øÃµÀÏ °ÍÀÔ´Ï´Ù.
¿©±â¼´Â ¼¼ºÎ»çÇ×À» »ý·«Çϰí, MySQLÀÇ ¼¼Á¾·ùÀÇ Çà±â¹Ý À̺¥Æ® ¾Ë¾Æ º¼ °ÍÀÔ´Ï´Ù.
- UPDATE_ROWS_EVENT
- DELETE_ROWS_EVENT
- INSERT_ROWS_EVENT
°¢°¢ÀÇ ·¹À̾ƿôÀº ¸Å¿ì À¯»çÇÕ´Ï´Ù. ¿ì¼± ¸ðµç À̺¥Æ®¿¡¼ µ¿ÀÏÇÑ Ç¥ÁØ Çì´õ°¡ ÀÖ½À´Ï´Ù.
class Log_event_header
{
public:
uint8_t reserved;
uint32_t timestamp;
uint8_t type_code;
uint32_t server_id;
uint32_t event_length;
uint32_t next_position;
uint16_t flags;
};
ÇàÀÇ Æ¯Á¤ÇÑ µ¥ÀÌÅÍ´Â ´ÙÀ½°ú °°½À´Ï´Ù.
class Row_event: public Binary_log_event
{
public:
uint64_t table_id;
uint16_t flags;
uint64_t columns_len;
uint32_t null_bits_len;
vector used_columns;
vector row;
[..]
};
¾Ë°íÀÖµíÀÌ, 'row' ¹éÅÍ·Î ºÎÅÍ ½ÇÁ¦ µ¥ÀÌÅ͸¦ °¡Áö°í ¿À´Â °ÍÀº ±×¸® Æò¹üÇÏÁö ¾Ê½À´Ï´Ù. ¿ì¸®ÀÇ ÇÁ·Î±×·¥ÀÌ »ç¿ëÇÒ ¼ö ÀÖ¾î¼ ¹«¾ð°¡·Î °ªÀ» ÃàÃâÇÒ ¼ö ÀÖ´Â ÆÄ¼¿Í °°Àº °ÍÀÌ ÇÊ¿äÇÕ´Ï´Ù.
¸®Çø®ÄÉÀ̼ǿ¡ »ç¿ëµÇ´Â µ¥ÀÌÅ͸ðµ¨Àº °¡º¿î °ª °´Ã¼ ÁÖÀ§¿¡ ±¸ÃàµÇ°í, ¾î¶² °ªÀº Row_of_fields·Î º¤ÅÍ Ä÷º¼Ç¿¡ ÀúÀåµË´Ï´Ù. °¢°¢ÀÇ Row_of_fields´Â Row_event_setÀÇ ÀϺÎÀÔ´Ï´Ù.
´Ù½ÃÇѹø óÀ½ºÎÅÍ »ìÆìº¸°Ú½À´Ï´Ù.
°¢°¢ÀÇ ÇàÀº Row_event_setÀ̶ó°í ºÒ¸®´Â ¿©·¯ Çà°ú Çʵå·Î ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù. Row_iterator´Â ¿ì¸®¿¡°Ô Çѹø¿¡ Çϳª¾¿ °¢°¢ÀÇ ÇàÀ» ¹Ýº¹ÇÏ´Â °ÍÀ» °¡´ÉÇÏ°Ô ÇÕ´Ï´Ù.
if (row_event->header()->type_code= UPDATE_ROWS_EVENT)
{
[..]
Row_event_set rows(row_event, table_map_event);
Row_event_set::iterator it= rows.begin();
Àá±ñ! table_map_eventÀº ¹«¾ùÀԴϱî? ±×°ÍÀº, °¢°¢ÀÇ Æ®·£Á§¼Ç°ú ¸ðµç Row event Àü¿¡ ¼¹ö¿¡ »ç¿ëµÇ´Â Å×ÀÌºí¿¡ ´ëÇÑ Á¤º¸¸¦ ¼±¾ðÇÑ descript-xor events¸¦ Àü´ÞÇÕ´Ï´Ù. ÀÌÁ¦ Å×ÀÌºí ´ë½Å Å×À̺í À̸§, µ¥ÀÌÅͺ£À̽º, ¸ðµç ´ÜÀÏ row event¿¡ ÀÖ´Â Àüü Çʵ尡 À妽º·Î ÂüÁ¶µÉ ¼ö Àֱ⶧¹®¿¡ ÁÁ½À´Ï´Ù. ¹°·Ð ¿ì¸®´Â ¸ÕÀú À妽º¸¦ ±¸ÃàÇØ¾ß ÇÕ´Ï´Ù. ¹°·Ð ¸ÕÀú À妽º¸¦ ±¸ÃàÇØ¾ßÇÕ´Ï´Ù. ¿À·¡ °É¸®Áö ¾ÊÀ»Å×´Ï Àá½Ã ±â´Þ·Á ÁÖ¼¼¿ä.
table mapÀ¸·Î ºÎÅÍÀÇ À妽º ±¸Ãà
¸ÕÀú map content ÄÜÅÙÃ÷ Çڵ鷯¸¦ µî·ÏÇϰí, ±×°ÍÀ» ½ºÅØ¿¡ ÀúÀåÇÕ´Ï´Ù. table map À̺¥Æ®¿¡ table_id¸¦ Ç¥ÁØ STL Áöµµ·Î »ç¿ëÇÕ´Ï´Ù.
class Table_map_handler : public Content_handler
{
public:
Binary_log_event *process_event(Table_map_event *event)
{
m_table_map.insert(Event_index_element(event->table_id,tm));
/*
Eat this event instead of passing it
on to the next handler.
*/
return NULL;
}
std::map m_table_map;
}
[..]
/* create an instance of the handler */
Table_map_handler table_index;
/* push content handler to stack */
binlog.content_handler_pipeline()->push_back(&table_index);
[..]
°¢°¢ÀÇ row event´Â ´ÙÀ½ º¯°æ Å×ÀÌºí¿¡ ´ëÇÑ À妽º¸¦ Æ÷ÇÔÇÕ´Ï´Ù:
[..]
/* get table id from the recently captured row event */
boost::uint64_t table_id= row_event->table_id;
Table_map_event *table_map_event=
table_index.m_table_map[table_id];
[..]
ÀÌÁ¦ Çà ¹Ýº¹À» Çϱâ À§ÇØ ÇÊ¿äÇÑ table map À̺¥Æ®°¡ »ý°å½À´Ï´Ù!
basic_transaction_parser.cpp ÆÄÀÏÀº ¾î¶² Æ®·£Á§¼Ç ±â°£ µ¿¾ÈÀÇ Áý°è table map ÄÜÅÙÃ÷ Çڵ鷯°¡ Æ÷ÇԵǾî ÀÖ½À´Ï´Ù. ´õ À¯¿ëÇÑ Å×À̺íÀε¦¼¸¦ ±¸ÃàÇϱâ À§Çؼ ÀÌ¿Í °°Àº ¿¹Á¦¸¦ »ç¿ëÇÕ´Ï´Ù.
¹Ýº¹ÀÇ ¸¶Áö¸· Çà
ÀÏ´Ü ¸ðµç ÇàÀ» ¹Ýº¹ÇÏ´Â °ÍÀÌ °¡´ÉÇÑ Row_iterator¸¦ ¸¸µé¾ú½À´Ï´Ù.
Row_event_set rows(row_event, table_map_event);
do {
Row_of_fields fields= *it;
if (event->get_event_type() == UPDATE_ROWS_EVENT)
{
++it;
Row_of_fields fields2= *it;
table_update(os.str(),fields,fields2);
}
[..]
} while (++it != rows.end());
Row_of_fields Ŭ·¡½º´Â ¿ì¸®¿¡°Ô Çѹø¿¡ ÇϳªÀÇ Çʵ带 ¹Ýº¹ÇÏ´Â °ÍÀ» °¡´ÉÇÏ°Ô ÇÕ´Ï´Ù.
void table_update (const string& table_name,
Row_of_fields &old_fields,
Row_of_fields &new_fields
{
int field_id= 0, string str;
Row_of_fields::iterator
field_it= new_fields.begin();
Converter converter;
do {
converter.to(str, *field_it);
cout << field_id << "= " << str;"
++field_it; ++field_id;
} while(field_it != new_fields.end());
}
Row_of_fieldsÀº ¾î¶² ÇÊ¿ä·Î ÇÏ´Â °ª¿¡ µû¶ó¼ ´Ù¸¥ Çü½ÄÀ¸·Î º¯È¯ ÇÒ ¼ö ÀÖ´Â °ª °´Ã¼¸¦ Æ÷ÇÔÇϰí ÀÖ½À´Ï´Ù. À§ÀÇ ¿¹Á¦¿¡¼´Â ÇÊµå °ªÀ» ÅØ½ºÆ®·Î º¯È¯ÇÏ¿© ȸéÀ¸·Î Àμâ ÇÒ ¼ö Àִ ǥÁØ º¯È¯ °´Ã¼°¡ »ç¿ëµË´Ï´Ù.
¿ì¸®ÀÇ µ¥ÀÌÅÍ ¸ðµ¨Àº ¾Æ·¡¼ À§·Î³ª À§¿¡¼ ¾Æ·¡·Î Àо´Â °ÍÀÌ´Ù.
°ü·Ã ¸µÅ©