=== modified file 'Percona-Server/include/mysql_com.h'
--- Percona-Server/include/mysql_com.h	2012-05-10 07:49:14 +0000
+++ Percona-Server/include/mysql_com.h	2013-01-22 16:40:34 +0000
@@ -152,6 +152,10 @@
 #define REFRESH_USER_STATS     0x800000L /* Refresh user stats my_hash table */
 #define REFRESH_CLIENT_STATS   0x1000000L /* Refresh client stats my_hash table */
 #define REFRESH_THREAD_STATS   0x2000000L /* Refresh thread stats my_hash table */
+#define REFRESH_FLUSH_PAGE_BITMAPS 0x400000L
+#define REFRESH_RESET_PAGE_BITMAPS 0x800000L
+
+#define PURGE_BITMAPS_TO_LSN 1
 
 #define CLIENT_LONG_PASSWORD	1	/* new more secure passwords */
 #define CLIENT_FOUND_ROWS	2	/* Found instead of affected rows */

=== removed file 'Percona-Server/mysql-test/include/delete_innodb_bitmaps.inc'
--- Percona-Server/mysql-test/include/delete_innodb_bitmaps.inc	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/include/delete_innodb_bitmaps.inc	1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
-# Remove all the InnoDB bitmap files. A temporary measure until RESET user request is implemented
-
-let $MYSQLD_DATADIR= `select @@datadir`;
-
---exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---shutdown_server 10
---source include/wait_until_disconnected.inc
-remove_files_wildcard $MYSQLD_DATADIR ib_modified_log*;
---enable_reconnect
---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---source include/wait_until_connected_again.inc

=== modified file 'Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp.result'
--- Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp.result	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp.result	2013-01-22 16:40:34 +0000
@@ -1,3 +1,4 @@
+RESET CHANGED_PAGE_BITMAPS;
 DROP TABLE IF EXISTS t1, t2;
 CREATE TABLE t1 (x INT) ENGINE=InnoDB;
 INSERT INTO t1 VALUES (1),(2),(3),(4),(5);

=== modified file 'Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_no_restart.result'
--- Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_no_restart.result	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_no_restart.result	2013-01-22 16:40:34 +0000
@@ -1,3 +1,4 @@
+RESET CHANGED_PAGE_BITMAPS;
 DROP TABLE IF EXISTS t1, t2;
 CREATE TABLE t1 (x INT) ENGINE=InnoDB;
 INSERT INTO t1 VALUES (1),(2),(3),(4),(5);

=== added file 'Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests.result'
--- Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests.result	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests.result	2013-01-22 16:40:34 +0000
@@ -0,0 +1,76 @@
+RESET CHANGED_PAGE_BITMAPS;
+DROP TABLE IF EXISTS t1;
+DELETE FROM mysql.user WHERE USER='mysqltest_1';
+FLUSH PRIVILEGES;
+CREATE TABLE t1 (x INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+FLUSH CHANGED_PAGE_BITMAPS;
+Before RESET:
+ib_modified_log_1
+ib_modified_log_2
+RESET CHANGED_PAGE_BITMAPS;
+After RESET:
+ib_modified_log_1
+RESET CHANGED_PAGE_BITMAPS;
+After 2nd RESET
+ib_modified_log_1
+After RESETs and restart:
+ib_modified_log_1
+ib_modified_log_2
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;
+After PURGE ... BEFORE 1:
+ib_modified_log_2
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+After PURGE ... BEFORE 100000000 and restart:
+ib_modified_log_4
+ib_modified_log_5
+PURGE CHANGED_PAGE_BITMAPS BEFORE 5+5;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '+5' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE -12;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-12' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1.2e-2;
+ERROR 42000: Only integers allowed as number here near '1.2e-2' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE t1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't1' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE "t1";
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"t1"' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE TRUE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRUE' at line 1
+PURGE CHANGED_PAGE_BITMAPS BEFORE NULL;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
+CREATE USER mysqltest_1@localhost;
+GRANT ALL ON *.* TO mysqltest_1@localhost;
+REVOKE SUPER ON *.* FROM mysqltest_1@localhost;
+FLUSH CHANGED_PAGE_BITMAPS;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+RESET CHANGED_PAGE_BITMAPS;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+DROP USER mysqltest_1@localhost;
+SELECT @@GLOBAL.innodb_track_changed_pages;
+@@GLOBAL.innodb_track_changed_pages
+0
+FLUSH CHANGED_PAGE_BITMAPS;
+Before the PURGE with tracking disabled
+ib_modified_log_4
+ib_modified_log_5
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;
+After the PURGE that deletes nothing:
+ib_modified_log_4
+ib_modified_log_5
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+After the PURGE that deletes everything:
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+After the repeated PURGE:
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+Before the RESET while tracking disabled:
+ib_modified_log_1
+ib_modified_log_2
+RESET CHANGED_PAGE_BITMAPS;
+After the RESET with tracking disabled:
+DROP TABLE t1;
+CREATE TABLE CHANGED_PAGE_BITMAPS (a INT);
+DROP TABLE CHANGED_PAGE_BITMAPS;

=== added file 'Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests_no_innodb.result'
--- Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests_no_innodb.result	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/r/percona_changed_page_bmp_requests_no_innodb.result	2013-01-22 16:40:34 +0000
@@ -0,0 +1,3 @@
+FLUSH CHANGED_PAGE_BITMAPS;
+RESET CHANGED_PAGE_BITMAPS;
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;

=== modified file 'Percona-Server/mysql-test/suite/innodb/r/percona_changed_pages.result'
--- Percona-Server/mysql-test/suite/innodb/r/percona_changed_pages.result	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/r/percona_changed_pages.result	2013-01-22 16:40:34 +0000
@@ -1,3 +1,4 @@
+RESET CHANGED_PAGE_BITMAPS;
 DROP TABLE IF EXISTS T1;
 CREATE TABLE T1 (F1 CHAR(255)) ENGINE=INNODB;
 1st interval end LSN greater than interval start LSN:

=== modified file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp.test'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp.test	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp.test	2013-01-22 16:40:34 +0000
@@ -13,7 +13,9 @@
 # Valgrind reports useless errors on very fast server shutdowns
 --source include/not_valgrind.inc
 
---source include/delete_innodb_bitmaps.inc
+# Delete any existing bitmaps
+--source include/restart_mysqld.inc
+RESET CHANGED_PAGE_BITMAPS;
 
 --disable_warnings
 DROP TABLE IF EXISTS t1, t2;

=== modified file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_no_restart.test'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_no_restart.test	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_no_restart.test	2013-01-22 16:40:34 +0000
@@ -2,7 +2,9 @@
 # percona_changed_page_bmp test, which contains the full functional tests.
 --source include/have_innodb.inc
 
---source include/delete_innodb_bitmaps.inc
+# Delete any existing bitmaps
+--source include/restart_mysqld.inc
+RESET CHANGED_PAGE_BITMAPS;
 
 --disable_warnings
 DROP TABLE IF EXISTS t1, t2;

=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests-master.opt'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests-master.opt	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests-master.opt	2013-01-22 16:40:34 +0000
@@ -0,0 +1,1 @@
+--innodb_track_changed_pages=TRUE

=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests.test'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests.test	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests.test	2013-01-22 16:40:34 +0000
@@ -0,0 +1,200 @@
+#
+# Tests for changed page tracking bitmaps: user requests.
+#
+--source include/have_innodb.inc
+
+# Delete any existing bitmaps
+--source include/restart_mysqld.inc
+RESET CHANGED_PAGE_BITMAPS;
+
+--source include/count_sessions.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DELETE FROM mysql.user WHERE USER='mysqltest_1';
+FLUSH PRIVILEGES;
+--enable_warnings
+
+CREATE TABLE t1 (x INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+
+#
+# Test FLUSH CHANGED_PAGE_BITMAPS.  Not much to test due to checkpointing non-determinism,
+# just see that it does not crash or return an error
+#
+FLUSH CHANGED_PAGE_BITMAPS;
+
+#
+# Test that RESET CHANGED_PAGE_BITMAPS works
+#
+
+# Have at least two bitmap files
+--source include/restart_mysqld.inc
+
+--echo Before RESET:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+RESET CHANGED_PAGE_BITMAPS;
+
+--echo After RESET:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+# Test consecutive RESET
+RESET CHANGED_PAGE_BITMAPS;
+--echo After 2nd RESET
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+# Check that the file sequence after RESET starts with 1 again
+--source include/restart_mysqld.inc
+
+--echo After RESETs and restart:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+#
+# Test that PURGE CHANGED_PAGE_BITMAPS BEFORE works.  We don't test partial PURGE
+# because it's hard to extract good LSN value for that.
+#
+
+# PURGE that deletes nothing
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;
+--echo After PURGE ... BEFORE 1:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+# PURGE that deletes everything
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+# Test consecutive PURGE
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+
+# Check that file sequence continues
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+--source include/restart_mysqld.inc
+--echo After PURGE ... BEFORE 100000000 and restart:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+#
+# Test malformed PURGE ... BEFORE
+#
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE 5+5;
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE -12;
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1.2e-2;
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE t1;
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE "t1";
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE TRUE;
+
+--error ER_PARSE_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE NULL;
+
+#
+# Test that non-privileged users cannot issue user requests
+#
+CREATE USER mysqltest_1@localhost;
+GRANT ALL ON *.* TO mysqltest_1@localhost;
+REVOKE SUPER ON *.* FROM mysqltest_1@localhost;
+
+connect (conn1,localhost,mysqltest_1,,);
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+FLUSH CHANGED_PAGE_BITMAPS;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+RESET CHANGED_PAGE_BITMAPS;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+
+connection default;
+disconnect conn1;
+
+--source include/wait_until_count_sessions.inc
+
+DROP USER mysqltest_1@localhost;
+
+#
+# Test FLUSH and PURGE requests with log tracking disabled
+#
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server 10
+--source include/wait_until_disconnected.inc
+--enable_reconnect
+--exec echo "restart:--innodb_track_changed_pages=FALSE" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/wait_until_connected_again.inc
+
+SELECT @@GLOBAL.innodb_track_changed_pages;
+
+FLUSH CHANGED_PAGE_BITMAPS;
+
+# The previous bitmap files should be present
+--echo Before the PURGE with tracking disabled
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;
+
+--echo After the PURGE that deletes nothing:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+
+--echo After the PURGE that deletes everything:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+PURGE CHANGED_PAGE_BITMAPS BEFORE 100000000;
+
+--echo After the repeated PURGE:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+#
+# Test RESET request with log tracking disabled
+#
+
+# Generate some bitmap data again
+--source include/restart_mysqld.inc
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+--source include/restart_mysqld.inc
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server 10
+--source include/wait_until_disconnected.inc
+--enable_reconnect
+--exec echo "restart:--innodb_track_changed_pages=FALSE" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/wait_until_connected_again.inc
+
+--echo Before the RESET while tracking disabled:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+RESET CHANGED_PAGE_BITMAPS;
+
+--echo After the RESET with tracking disabled:
+--replace_regex /_[[:digit:]]+\.xdb$//
+list_files $MYSQLD_DATADIR ib_modified_log*;
+
+DROP TABLE t1;
+
+#
+# Test that the new keyword does not preclude its use as identifier
+#
+CREATE TABLE CHANGED_PAGE_BITMAPS (a INT);
+DROP TABLE CHANGED_PAGE_BITMAPS;

=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb-master.opt'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb-master.opt	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb-master.opt	2013-01-22 16:40:34 +0000
@@ -0,0 +1,1 @@
+--skip-innodb

=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb.test'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb.test	1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_page_bmp_requests_no_innodb.test	2013-01-22 16:40:34 +0000
@@ -0,0 +1,7 @@
+#
+# Test that changed page tracking user requests are parsed without InnoDB
+#
+FLUSH CHANGED_PAGE_BITMAPS;
+RESET CHANGED_PAGE_BITMAPS;
+PURGE CHANGED_PAGE_BITMAPS BEFORE 1;
+

=== modified file 'Percona-Server/mysql-test/suite/innodb/t/percona_changed_pages.test'
--- Percona-Server/mysql-test/suite/innodb/t/percona_changed_pages.test	2012-11-25 09:30:58 +0000
+++ Percona-Server/mysql-test/suite/innodb/t/percona_changed_pages.test	2013-01-22 16:40:34 +0000
@@ -4,7 +4,9 @@
 
 --source include/have_innodb.inc
 
---source include/delete_innodb_bitmaps.inc
+# Delete any existing bitmaps
+--source include/restart_mysqld.inc
+RESET CHANGED_PAGE_BITMAPS;
 
 --disable_warnings
 DROP TABLE IF EXISTS T1;

=== modified file 'Percona-Server/sql/handler.cc'
--- Percona-Server/sql/handler.cc	2013-01-17 22:50:22 +0000
+++ Percona-Server/sql/handler.cc	2013-01-22 16:40:34 +0000
@@ -5125,6 +5125,42 @@
   return result;
 }
 
+static my_bool flush_changed_page_bitmaps_handlerton(THD *unused1,
+                                                     plugin_ref plugin,
+                                                     void *unused2)
+{
+  handlerton *hton= plugin_data(plugin, handlerton *);
+
+  if (hton->flush_changed_page_bitmaps == NULL)
+    return FALSE;
+
+  return hton->flush_changed_page_bitmaps();
+}
+
+bool ha_flush_changed_page_bitmaps()
+{
+  return plugin_foreach(NULL, flush_changed_page_bitmaps_handlerton,
+                        MYSQL_STORAGE_ENGINE_PLUGIN, NULL);
+}
+
+static my_bool purge_changed_page_bitmaps_handlerton(THD *unused1,
+                                                     plugin_ref plugin,
+                                                     void *lsn)
+{
+  handlerton *hton= plugin_data(plugin, handlerton *);
+
+  if (hton->purge_changed_page_bitmaps == NULL)
+    return FALSE;
+
+  return hton->purge_changed_page_bitmaps(*(ulonglong *)lsn);
+}
+
+bool ha_purge_changed_page_bitmaps(ulonglong lsn)
+{
+  return plugin_foreach(NULL, purge_changed_page_bitmaps_handlerton,
+                        MYSQL_STORAGE_ENGINE_PLUGIN, &lsn);
+}
+
 /*
   Function to check if the conditions for row-based binlogging is
   correct for the table.

=== modified file 'Percona-Server/sql/handler.h'
--- Percona-Server/sql/handler.h	2013-01-09 23:45:25 +0000
+++ Percona-Server/sql/handler.h	2013-01-22 16:40:34 +0000
@@ -842,6 +842,8 @@
    int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables, 
                         class Item *cond, 
                         enum enum_schema_tables);
+   my_bool (*flush_changed_page_bitmaps)(void);
+   my_bool (*purge_changed_page_bitmaps)(ulonglong lsn);
    uint32 flags;                                /* global handler flags */
    /*
       Those handlerton functions below are properly initialized at handler
@@ -2390,6 +2392,9 @@
 int ha_prepare(THD *thd);
 int ha_recover(HASH *commit_list);
 
+bool ha_flush_changed_page_bitmaps();
+bool ha_purge_changed_page_bitmaps(ulonglong lsn);
+
 /* transactions: these functions never call handlerton functions directly */
 int ha_enable_transaction(THD *thd, bool on);
 

=== modified file 'Percona-Server/sql/lex.h'
--- Percona-Server/sql/lex.h	2012-05-10 07:49:14 +0000
+++ Percona-Server/sql/lex.h	2013-01-22 16:40:34 +0000
@@ -103,6 +103,7 @@
   { "CHAIN",		SYM(CHAIN_SYM)},
   { "CHANGE",		SYM(CHANGE)},
   { "CHANGED",		SYM(CHANGED)},
+  { "CHANGED_PAGE_BITMAPS",	SYM(CHANGED_PAGE_BITMAPS_SYM)},
   { "CHAR",		SYM(CHAR_SYM)},
   { "CHARACTER",	SYM(CHAR_SYM)},
   { "CHARSET",		SYM(CHARSET)},

=== modified file 'Percona-Server/sql/sql_parse.cc'
--- Percona-Server/sql/sql_parse.cc	2013-01-09 23:45:25 +0000
+++ Percona-Server/sql/sql_parse.cc	2013-01-22 16:40:34 +0000
@@ -2320,9 +2320,35 @@
   {
     if (check_global_access(thd, SUPER_ACL))
       goto error;
-    /* PURGE MASTER LOGS TO 'file' */
-    res = purge_master_logs(thd, lex->to_log);
-    break;
+    if (lex->type == 0)
+    {
+      /* PURGE MASTER LOGS TO 'file' */
+      res = purge_master_logs(thd, lex->to_log);
+      break;
+    }
+    if (lex->type == PURGE_BITMAPS_TO_LSN)
+    {
+      /* PURGE CHANGED_PAGE_BITMAPS BEFORE lsn */
+      ulonglong lsn= 0;
+      Item *it= (Item *)lex->value_list.head();
+      if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)
+          || it->null_value)
+      {
+        my_error(ER_WRONG_ARGUMENTS, MYF(0),
+                 "PURGE CHANGED_PAGE_BITMAPS BEFORE");
+        goto error;
+      }
+      lsn= it->val_uint();
+      res= ha_purge_changed_page_bitmaps(lsn);
+      if (res)
+      {
+        my_error(ER_LOG_PURGE_UNKNOWN_ERR, MYF(0),
+                 "PURGE CHANGED_PAGE_BITMAPS BEFORE");
+        goto error;
+      }
+      my_ok(thd);
+      break;
+    }
   }
   case SQLCOM_PURGE_BEFORE:
   {
@@ -3782,7 +3808,14 @@
   case SQLCOM_FLUSH:
   {
     int write_to_binlog;
-    if (check_global_access(thd,RELOAD_ACL))
+
+    if (lex->type & REFRESH_FLUSH_PAGE_BITMAPS
+        || lex->type & REFRESH_RESET_PAGE_BITMAPS)
+    {
+      if (check_global_access(thd, SUPER_ACL))
+          goto error;
+    }
+    else if (check_global_access(thd, RELOAD_ACL))
       goto error;
 
     if (first_table && lex->type & REFRESH_READ_LOCK)

=== modified file 'Percona-Server/sql/sql_reload.cc'
--- Percona-Server/sql/sql_reload.cc	2012-04-18 23:26:01 +0000
+++ Percona-Server/sql/sql_reload.cc	2013-01-22 16:40:34 +0000
@@ -362,6 +362,22 @@
     }
     mysql_mutex_unlock(&LOCK_global_user_client_stats);
   }
+  if (options & REFRESH_FLUSH_PAGE_BITMAPS)
+  {
+    result= ha_flush_changed_page_bitmaps();
+    if (result)
+    {
+      my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH CHANGED_PAGE_BITMAPS");
+    }
+  }
+  if (options & REFRESH_RESET_PAGE_BITMAPS)
+  {
+    result= ha_purge_changed_page_bitmaps(0);
+    if (result)
+    {
+      my_error(ER_UNKNOWN_ERROR, MYF(0), "RESET CHANGED_PAGE_BITMAPS");
+    }
+  }
  if (*write_to_binlog != -1)
    *write_to_binlog= tmp_write_to_binlog;
  /*

=== modified file 'Percona-Server/sql/sql_yacc.yy'
--- Percona-Server/sql/sql_yacc.yy	2013-01-09 23:45:25 +0000
+++ Percona-Server/sql/sql_yacc.yy	2013-01-22 16:40:34 +0000
@@ -858,6 +858,7 @@
 %token  CHAIN_SYM                     /* SQL-2003-N */
 %token  CHANGE
 %token  CHANGED
+%token  CHANGED_PAGE_BITMAPS_SYM      /* MYSQL      */
 %token  CHARSET
 %token  CHAR_SYM                      /* SQL-2003-R */
 %token  CHECKSUM_SYM
@@ -11457,6 +11458,8 @@
           { Lex->type|= REFRESH_DES_KEY_FILE; }
         | RESOURCES
           { Lex->type|= REFRESH_USER_RESOURCES; }
+        | CHANGED_PAGE_BITMAPS_SYM
+          { Lex->type|= REFRESH_FLUSH_PAGE_BITMAPS; }
         ;
 
 opt_table_list:
@@ -11484,6 +11487,8 @@
           slave_reset_options { }
         | MASTER_SYM          { Lex->type|= REFRESH_MASTER; }
         | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;}
+        | CHANGED_PAGE_BITMAPS_SYM
+          { Lex->type |= REFRESH_RESET_PAGE_BITMAPS; }
         ;
 
 slave_reset_options:
@@ -11504,6 +11509,13 @@
 
 purge_options:
           master_or_binary LOGS_SYM purge_option
+        | CHANGED_PAGE_BITMAPS_SYM BEFORE_SYM real_ulonglong_num
+          {
+            LEX *lex= Lex;
+            lex->value_list.empty();
+            lex->value_list.push_front(new Item_uint($3));
+            lex->type= PURGE_BITMAPS_TO_LSN;
+          }
         ;
 
 purge_option:
@@ -12594,6 +12606,7 @@
         | CATALOG_NAME_SYM         {}
         | CHAIN_SYM                {}
         | CHANGED                  {}
+        | CHANGED_PAGE_BITMAPS_SYM {}
         | CIPHER_SYM               {}
         | CLIENT_STATS_SYM         {}
         | CLIENT_SYM               {}

=== modified file 'Percona-Server/storage/innobase/handler/ha_innodb.cc'
--- Percona-Server/storage/innobase/handler/ha_innodb.cc	2013-01-18 03:34:53 +0000
+++ Percona-Server/storage/innobase/handler/ha_innodb.cc	2013-01-22 16:40:34 +0000
@@ -85,6 +85,7 @@
 #include "row0sel.h"
 #include "row0upd.h"
 #include "log0log.h"
+#include "log0online.h"
 #include "lock0lock.h"
 #include "dict0crea.h"
 #include "btr0cur.h"
@@ -297,6 +298,7 @@
 	{&ibuf_pessimistic_insert_mutex_key,
 		 "ibuf_pessimistic_insert_mutex", 0},
 	{&kernel_mutex_key, "kernel_mutex", 0},
+	{&log_bmp_sys_mutex_key, "log_bmp_sys_mutex", 0},
 	{&log_sys_mutex_key, "log_sys_mutex", 0},
 #  ifdef UNIV_MEM_DEBUG
 	{&mem_hash_mutex_key, "mem_hash_mutex", 0},
@@ -438,6 +440,25 @@
 innobase_alter_table_flags(
 /*=======================*/
 	uint	flags);
+/************************************************************//**
+Synchronously read and parse the redo log up to the last
+checkpoint to write the changed page bitmap.
+@return 0 to indicate success.  Current implementation cannot fail. */
+static
+my_bool
+innobase_flush_changed_page_bitmaps();
+/*==================================*/
+/************************************************************//**
+Delete all the bitmap files for data less than the specified LSN.
+If called with lsn == 0 (i.e. set by RESET request) or
+IB_ULONGLONG_MAX, restart the bitmap file sequence, otherwise
+continue it.
+@return 0 to indicate success, 1 for failure. */
+static
+my_bool
+innobase_purge_changed_page_bitmaps(
+/*================================*/
+	ulonglong lsn);	/*!< in: LSN to purge files up to */
 
 static const char innobase_hton_name[]= "InnoDB";
 
@@ -2663,6 +2684,10 @@
         innobase_hton->flags=HTON_NO_FLAGS;
         innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
 	innobase_hton->alter_table_flags = innobase_alter_table_flags;
+	innobase_hton->flush_changed_page_bitmaps
+		= innobase_flush_changed_page_bitmaps;
+	innobase_hton->purge_changed_page_bitmaps
+		= innobase_purge_changed_page_bitmaps;
 
 	ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
 
@@ -3282,6 +3307,36 @@
 		| HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE);
 }
 
+/************************************************************//**
+Synchronously read and parse the redo log up to the last
+checkpoint to write the changed page bitmap.
+@return 0 to indicate success.  Current implementation cannot fail. */
+static
+my_bool
+innobase_flush_changed_page_bitmaps()
+/*=================================*/
+{
+	if (srv_track_changed_pages) {
+		os_event_reset(srv_checkpoint_completed_event);
+		log_online_follow_redo_log();
+	}
+	return FALSE;
+}
+
+/************************************************************//**
+Delete all the bitmap files for data less than the specified LSN.
+If called with lsn == IB_ULONGLONG_MAX (i.e. set by RESET request),
+restart the bitmap file sequence, otherwise continue it.
+@return 0 to indicate success, 1 for failure. */
+static
+my_bool
+innobase_purge_changed_page_bitmaps(
+/*================================*/
+	ulonglong lsn)	/*!< in: LSN to purge files up to */
+{
+	return (my_bool)log_online_purge_changed_page_bitmaps(lsn);
+}
+
 /****************************************************************//**
 Copy the current replication position from MySQL to a transaction. */
 static

=== modified file 'Percona-Server/storage/innobase/include/log0online.h'
--- Percona-Server/storage/innobase/include/log0online.h	2012-11-25 09:29:43 +0000
+++ Percona-Server/storage/innobase/include/log0online.h	2013-01-22 16:40:34 +0000
@@ -41,23 +41,49 @@
 Initializes the online log following subsytem. */
 UNIV_INTERN
 void
-log_online_read_init();
-/*===================*/
+log_online_read_init(void);
+/*=======================*/
 
 /*********************************************************************//**
 Shuts down the online log following subsystem. */
 UNIV_INTERN
 void
-log_online_read_shutdown();
-/*=======================*/
+log_online_read_shutdown(void);
+/*===========================*/
 
 /*********************************************************************//**
 Reads and parses the redo log up to last checkpoint LSN to build the changed
 page bitmap which is then written to disk.  */
 UNIV_INTERN
 void
-log_online_follow_redo_log();
-/*=========================*/
+log_online_follow_redo_log(void);
+/*=============================*/
+
+/************************************************************//**
+Delete all the bitmap files for data less than the specified LSN.
+If called with lsn == 0 (i.e. set by RESET request) or
+IB_ULONGLONG_MAX, restart the bitmap file sequence, otherwise
+continue it.
+
+@return FALSE to indicate success, TRUE for failure. */
+UNIV_INTERN
+ibool
+log_online_purge_changed_page_bitmaps(
+/*==================================*/
+	ib_uint64_t lsn);	/*!<in: LSN to purge files up to */
+
+/************************************************************//**
+Delete all the bitmap files for data less than the specified LSN.
+If called with lsn == 0 (i.e. set by RESET request) or
+IB_ULONGLONG_MAX, restart the bitmap file sequence, otherwise
+continue it.
+
+@return FALSE to indicate success, TRUE for failure. */
+UNIV_INTERN
+ibool
+log_online_purge_changed_page_bitmaps(
+/*==================================*/
+	ib_uint64_t lsn);	/*!<in: LSN to purge files up to */
 
 #define LOG_BITMAP_ITERATOR_START_LSN(i) \
 	((i).start_lsn)

=== modified file 'Percona-Server/storage/innobase/include/sync0sync.h'
--- Percona-Server/storage/innobase/include/sync0sync.h	2012-05-10 07:49:14 +0000
+++ Percona-Server/storage/innobase/include/sync0sync.h	2013-01-22 16:40:34 +0000
@@ -89,6 +89,7 @@
 extern mysql_pfs_key_t	ibuf_bitmap_mutex_key;
 extern mysql_pfs_key_t	ibuf_mutex_key;
 extern mysql_pfs_key_t	ibuf_pessimistic_insert_mutex_key;
+extern mysql_pfs_key_t	log_bmp_sys_mutex_key;
 extern mysql_pfs_key_t	log_sys_mutex_key;
 extern mysql_pfs_key_t	log_flush_order_mutex_key;
 extern mysql_pfs_key_t	kernel_mutex_key;
@@ -672,6 +673,7 @@
 #define	SYNC_TRX_LOCK_HEAP	298
 #define SYNC_TRX_SYS_HEADER	290
 #define	SYNC_PURGE_QUEUE	200
+#define SYNC_LOG_ONLINE		175
 #define SYNC_LOG		170
 #define SYNC_LOG_FLUSH_ORDER	156
 #define SYNC_RECV		168

=== modified file 'Percona-Server/storage/innobase/log/log0online.c'
--- Percona-Server/storage/innobase/log/log0online.c	2013-01-04 15:24:45 +0000
+++ Percona-Server/storage/innobase/log/log0online.c	2013-01-22 16:40:34 +0000
@@ -36,6 +36,11 @@
 
 enum { FOLLOW_SCAN_SIZE = 4 * (UNIV_PAGE_SIZE_MAX) };
 
+#ifdef UNIV_PFS_MUTEX
+/* Key to register log_bmp_sys->mutex with PFS */
+UNIV_INTERN mysql_pfs_key_t	log_bmp_sys_mutex_key;
+#endif /* UNIV_PFS_MUTEX */
+
 /** Log parsing and bitmap output data structure */
 struct log_bitmap_struct {
 	byte		read_buf[FOLLOW_SCAN_SIZE];
@@ -69,6 +74,7 @@
 					both the correct type and the tree does
 					not mind its overwrite during
 					rbt_next() tree traversal. */
+	mutex_t		mutex;		/*!< mutex protecting all the fields.*/
 };
 
 /* The log parsing and bitmap output struct instance */
@@ -172,6 +178,8 @@
 	byte		search_page[MODIFIED_PAGE_BLOCK_SIZE];
 	byte		*page_ptr;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	ut_a(space != ULINT_UNDEFINED);
 	ut_a(page_no != ULINT_UNDEFINED);
 
@@ -312,8 +320,8 @@
 @return the last fully tracked LSN */
 static
 ib_uint64_t
-log_online_read_last_tracked_lsn()
-/*==============================*/
+log_online_read_last_tracked_lsn(void)
+/*==================================*/
 {
 	byte		page[MODIFIED_PAGE_BLOCK_SIZE];
 	ibool		is_last_page	= FALSE;
@@ -487,8 +495,8 @@
 Create a new empty bitmap output file.  */
 static
 void
-log_online_start_bitmap_file()
-/*==========================*/
+log_online_start_bitmap_file(void)
+/*==============================*/
 {
 	ibool	success;
 
@@ -518,7 +526,10 @@
 	ib_uint64_t	next_file_start_lsn)	/*!<in: the start LSN name
 						part */
 {
-	os_file_close(log_bmp_sys->out.file);
+	if (log_bmp_sys->out.file != -1) {
+		os_file_close(log_bmp_sys->out.file);
+		log_bmp_sys->out.file = -1;
+	}
 	log_bmp_sys->out_seq_num++;
 	log_online_make_bitmap_name(next_file_start_lsn);
 	log_online_start_bitmap_file();
@@ -556,8 +567,8 @@
 Initialize the online log following subsytem. */
 UNIV_INTERN
 void
-log_online_read_init()
-/*==================*/
+log_online_read_init(void)
+/*======================*/
 {
 	ibool		success;
 	ib_uint64_t	tracking_start_lsn
@@ -566,13 +577,16 @@
 	os_file_stat_t	bitmap_dir_file_info;
 	ib_uint64_t	last_file_start_lsn	= MIN_TRACKED_LSN;
 
-	/* Assert (could be compile-time assert) that bitmap data start and end
-	in a bitmap block is 8-byte aligned */
-	ut_a(MODIFIED_PAGE_BLOCK_BITMAP % 8 == 0);
-	ut_a(MODIFIED_PAGE_BLOCK_BITMAP_LEN % 8 == 0);
+	/* Bitmap data start and end in a bitmap block must be 8-byte
+	aligned. */
+	compile_time_assert(MODIFIED_PAGE_BLOCK_BITMAP % 8 == 0);
+	compile_time_assert(MODIFIED_PAGE_BLOCK_BITMAP_LEN % 8 == 0);
 
 	log_bmp_sys = ut_malloc(sizeof(*log_bmp_sys));
 
+	mutex_create(log_bmp_sys_mutex_key, &log_bmp_sys->mutex,
+		     SYNC_LOG_ONLINE);
+
 	/* Enumerate existing bitmap files to either open the last one to get
 	the last tracked LSN either to find that there are none and start
 	tracking from scratch.  */
@@ -701,12 +715,15 @@
 Shut down the online log following subsystem. */
 UNIV_INTERN
 void
-log_online_read_shutdown()
-/*======================*/
+log_online_read_shutdown(void)
+/*==========================*/
 {
 	ib_rbt_node_t *free_list_node = log_bmp_sys->page_free_list;
 
-	os_file_close(log_bmp_sys->out.file);
+	if (log_bmp_sys->out.file != -1) {
+		os_file_close(log_bmp_sys->out.file);
+		log_bmp_sys->out.file = -1;
+	}
 
 	rbt_free(log_bmp_sys->modified_pages);
 
@@ -716,6 +733,8 @@
 		free_list_node = next;
 	}
 
+	mutex_free(&log_bmp_sys->mutex);
+
 	ut_free(log_bmp_sys);
 }
 
@@ -759,14 +778,16 @@
 buffer. */
 static
 void
-log_online_parse_redo_log()
-/*=======================*/
+log_online_parse_redo_log(void)
+/*===========================*/
 {
 	byte *ptr = log_bmp_sys->parse_buf;
 	byte *end = log_bmp_sys->parse_buf_end;
 
 	ulint len = 0;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	while (ptr != end
 	       && log_bmp_sys->next_parse_lsn < log_bmp_sys->end_lsn) {
 
@@ -857,6 +878,8 @@
 	ulint actual_data_len = (end_offset >= start_offset)
 		? end_offset - start_offset : 0;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	ut_memcpy(log_bmp_sys->parse_buf_end, log_block + start_offset,
 		  actual_data_len);
 
@@ -881,6 +904,8 @@
 {
 	ulint block_data_len;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	block_data_len = log_block_get_data_len(log_block);
 
 	ut_ad(block_data_len % OS_FILE_LOG_BLOCK_SIZE == 0
@@ -907,6 +932,8 @@
 	byte* log_block_end = log_bmp_sys->read_buf
 		+ (block_end_lsn - block_start_lsn);
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	mutex_enter(&log_sys->mutex);
 	log_group_read_log_seg(LOG_RECOVER, log_bmp_sys->read_buf,
 			       group, block_start_lsn, block_end_lsn);
@@ -969,6 +996,8 @@
 	ib_uint64_t block_start_lsn = contiguous_lsn;
 	ib_uint64_t block_end_lsn;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	log_bmp_sys->next_parse_lsn = log_bmp_sys->start_lsn;
 	log_bmp_sys->parse_buf_end = log_bmp_sys->parse_buf;
 
@@ -1005,6 +1034,8 @@
 {
 	ibool	success;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	success = os_file_write(log_bmp_sys->out.name, log_bmp_sys->out.file,
 				block,
 				(ulint)(log_bmp_sys->out.offset & 0xFFFFFFFF),
@@ -1038,12 +1069,14 @@
 bitmap tree and recycles its nodes to the free list. */
 static
 void
-log_online_write_bitmap()
-/*=====================*/
+log_online_write_bitmap(void)
+/*=========================*/
 {
 	ib_rbt_node_t		*bmp_tree_node;
 	const ib_rbt_node_t	*last_bmp_tree_node;
 
+	ut_ad(mutex_own(&log_bmp_sys->mutex));
+
 	if (log_bmp_sys->out.offset >= srv_max_bitmap_file_size) {
 		log_online_rotate_bitmap_file(log_bmp_sys->start_lsn);
 	}
@@ -1084,18 +1117,21 @@
 page bitmap which is then written to disk.  */
 UNIV_INTERN
 void
-log_online_follow_redo_log()
-/*========================*/
+log_online_follow_redo_log(void)
+/*============================*/
 {
 	ib_uint64_t	contiguous_start_lsn;
 	log_group_t*	group;
 
+	mutex_enter(&log_bmp_sys->mutex);
+
 	/* Grab the LSN of the last checkpoint, we will parse up to it */
 	mutex_enter(&(log_sys->mutex));
 	log_bmp_sys->end_lsn = log_sys->last_checkpoint_lsn;
 	mutex_exit(&(log_sys->mutex));
 
 	if (log_bmp_sys->end_lsn == log_bmp_sys->start_lsn) {
+		mutex_exit(&log_bmp_sys->mutex);
 		return;
 	}
 
@@ -1117,6 +1153,8 @@
 	log_online_write_bitmap();
 	log_bmp_sys->start_lsn = log_bmp_sys->end_lsn;
 	log_set_tracked_lsn(log_bmp_sys->start_lsn);
+
+	mutex_exit(&log_bmp_sys->mutex);
 }
 
 /*********************************************************************//**
@@ -1514,3 +1552,76 @@
 
 	return TRUE;
 }
+
+/************************************************************//**
+Delete all the bitmap files for data less than the specified LSN.
+If called with lsn == 0 (i.e. set by RESET request) or
+IB_ULONGLONG_MAX, restart the bitmap file sequence, otherwise
+continue it.
+
+@return FALSE to indicate success, TRUE for failure. */
+UNIV_INTERN
+ibool
+log_online_purge_changed_page_bitmaps(
+/*==================================*/
+	ib_uint64_t lsn)	/*!< in: LSN to purge files up to */
+{
+	log_online_bitmap_file_range_t	bitmap_files;
+	size_t				i;
+	ibool				result = FALSE;
+
+	if (lsn == 0) {
+		lsn = IB_ULONGLONG_MAX;
+	}
+
+	if (srv_track_changed_pages) {
+		/* User requests might happen with both enabled and disabled
+		tracking */
+		mutex_enter(&log_bmp_sys->mutex);
+	}
+
+	if (!log_online_setup_bitmap_file_range(&bitmap_files, 0, lsn)) {
+		if (srv_track_changed_pages) {
+			mutex_exit(&log_bmp_sys->mutex);
+		}
+		return TRUE;
+	}
+
+	if (srv_track_changed_pages && lsn >= log_bmp_sys->end_lsn) {
+		/* If we have to delete the current output file, close it
+		first. */
+		os_file_close(log_bmp_sys->out.file);
+		log_bmp_sys->out.file = -1;
+	}
+
+	for (i = 0; i < bitmap_files.count; i++) {
+		if (bitmap_files.files[i].seq_num == 0
+		    || bitmap_files.files[i].start_lsn >= lsn) {
+			break;
+		}
+		if (!os_file_delete_if_exists(bitmap_files.files[i].name)) {
+			os_file_get_last_error(TRUE);
+			result = TRUE;
+			break;
+		}
+	}
+
+	if (srv_track_changed_pages) {
+		if (lsn > log_bmp_sys->end_lsn) {
+			if (lsn == IB_ULONGLONG_MAX) {
+				/* RESET restarts the sequence */
+				log_bmp_sys->out_seq_num = 0;
+				log_online_rotate_bitmap_file(0);
+			} else {
+				/* PURGE continues the sequence */
+				log_online_rotate_bitmap_file
+					(log_bmp_sys->end_lsn);
+			}
+		}
+
+		mutex_exit(&log_bmp_sys->mutex);
+	}
+
+	free(bitmap_files.files);
+	return result;
+}

