From: Jon Olav Hauglid Date: December 20 2010 5:17pm Subject: bzr commit into mysql-5.5-bugteam branch (jon.hauglid:3217) Bug#42230 List-Archive: http://lists.mysql.com/commits/127333 X-Bug: 42230 Message-Id: <201012201737.oBKHbvVJ008882@acsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0616597363704944583==" --===============0616597363704944583== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/x/mysql-5.5-bugteam-bug42230/ based on revid:bjorn.munch@stripped 3217 Jon Olav Hauglid 2010-12-20 Bug #42230 during add index, cannot do queries on storage engines that implement add_index The problem was that ALTER TABLE blocked reads on an InnoDB table while adding a secondary index, even if this was not needed. It is only needed for the final step where the .frm file is updated. The reason queries were blocked, was that ALTER TABLE upgraded the metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to MDL_EXCLUSIVE (which blocks all accesses) before index creation. The way the server handles index creation, is that storage engines publish their capabilities to the server and the server determines which of the following three ways this can be handled: 1) build a new version of the table; 2) change the existing table but with exclusive metadata lock; 3) change the existing table but without metadata lock upgrade. For InnoDB and secondary index creation, option 3) should have been selected. However this failed for two reasons. First, InnoDB did not publish this capability properly. Second, the ALTER TABLE code failed to made proper use of the information supplied by the storage engine. A variable need_lock_for_indexes was set accordingly, but was not later used. This patch fixes this problem by only doing metadata lock upgrade before index creation/deletion if this variable has been set. This patch also changes some of the related terminology used in the code. Specifically the use of "fast" and "online" with respect to ALTER TABLE. "Fast" was used to indicate that an ALTER TABLE operation could be done without involving a temporary table. "Fast" has been renamed "in-place" to more accurately describe the behavior. "Online" meant that the operation could be done without taking a table lock. However, in the current implementation writes are always prohibited during ALTER TABLE and an exclusive metadata lock is held while updating the .frm, so ALTER TABLE was not completely online. This patch replaces "online" with "in-place", with additional comments indicating if concurrent reads are allowed during index creation/deletion or not. An important part of this update of terminology is renaming of the handler flags used by handlers to indicate if index creation/deletion can be done in-place and if concurrent reads are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES flag has been renamed HA_INPLACE_ADD_INDEX_NO_READ_WRITE, while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE. Note that this is a rename to clarify current behavior, the flag values have not changed and no flags have been removed or added. Test case added to innodb_mysql_sync.test. modified: mysql-test/r/innodb_mysql_sync.result mysql-test/t/innodb_mysql_sync.test sql/ha_partition.cc sql/handler.h sql/sql_table.cc storage/innobase/handler/ha_innodb.cc === modified file 'mysql-test/r/innodb_mysql_sync.result' --- a/mysql-test/r/innodb_mysql_sync.result 2010-06-25 07:07:18 +0000 +++ b/mysql-test/r/innodb_mysql_sync.result 2010-12-20 17:16:55 +0000 @@ -66,3 +66,28 @@ SELECT ((@id := id) - id) FROM t2; KILL @id; SET DEBUG_SYNC= "now SIGNAL killed"; DROP TABLE t1, t2; +SET DEBUG_SYNC= "RESET"; +# +# Bug#42230 during add index, cannot do queries on storage engines +# that implement add_index +# +DROP DATABASE IF EXISTS db1; +# Connection default +CREATE DATABASE db1; +CREATE TABLE db1.t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, value INT) engine=innodb; +INSERT INTO db1.t1(value) VALUES (1), (2); +SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query"; +# Sending: +ALTER TABLE db1.t1 ADD INDEX(value); +# Connection con1 +SET DEBUG_SYNC= "now WAIT_FOR manage"; +USE db1; +SELECT * FROM t1; +id value +1 1 +2 2 +SET DEBUG_SYNC= "now SIGNAL query"; +# Connection default +# Reaping: ALTER TABLE db1.t1 ADD INDEX(value) +DROP DATABASE db1; +SET DEBUG_SYNC= "RESET"; === modified file 'mysql-test/t/innodb_mysql_sync.test' --- a/mysql-test/t/innodb_mysql_sync.test 2010-06-25 07:07:18 +0000 +++ b/mysql-test/t/innodb_mysql_sync.test 2010-12-20 17:16:55 +0000 @@ -104,6 +104,42 @@ SELECT ((@id := id) - id) FROM t2; KILL @id; SET DEBUG_SYNC= "now SIGNAL killed"; DROP TABLE t1, t2; +disconnect con1; +SET DEBUG_SYNC= "RESET"; + + +--echo # +--echo # Bug#42230 during add index, cannot do queries on storage engines +--echo # that implement add_index +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +--echo # Connection default +CREATE DATABASE db1; +CREATE TABLE db1.t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, value INT) engine=innodb; +INSERT INTO db1.t1(value) VALUES (1), (2); +SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query"; +--echo # Sending: +--send ALTER TABLE db1.t1 ADD INDEX(value) + +--echo # Connection con1 +connect(con1,localhost,root); +SET DEBUG_SYNC= "now WAIT_FOR manage"; +# Neither of these two statements should be blocked +USE db1; +SELECT * FROM t1; +SET DEBUG_SYNC= "now SIGNAL query"; + +--echo # Connection default +connection default; +--echo # Reaping: ALTER TABLE db1.t1 ADD INDEX(value) +--reap +DROP DATABASE db1; +disconnect con1; +SET DEBUG_SYNC= "RESET"; # Check that all connections opened by test cases in this file are really === modified file 'sql/ha_partition.cc' --- a/sql/ha_partition.cc 2010-12-17 11:11:34 +0000 +++ b/sql/ha_partition.cc 2010-12-20 17:16:55 +0000 @@ -6430,28 +6430,28 @@ uint ha_partition::alter_table_flags(uin already altered, partitions. So both ADD and DROP can only be supported in pairs. */ - flags_to_check= HA_ONLINE_ADD_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_INDEX; - flags_to_check|= HA_ONLINE_DROP_INDEX; + flags_to_check= HA_INPLACE_ADD_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX; - flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX; + flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_PK_INDEX; - flags_to_check|= HA_ONLINE_DROP_PK_INDEX; + flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; DBUG_RETURN(flags_to_return); === modified file 'sql/handler.h' --- a/sql/handler.h 2010-11-05 11:01:10 +0000 +++ b/sql/handler.h 2010-12-20 17:16:55 +0000 @@ -172,28 +172,31 @@ bits in alter_table_flags: */ /* - These bits are set if different kinds of indexes can be created - off-line without re-create of the table (but with a table lock). + These bits are set if different kinds of indexes can be created or dropped + in-place without re-creating the table using a temporary table. + NO_READ_WRITE indicates that the handler needs concurrent reads and writes + of table data to be blocked. Partitioning needs both ADD and DROP to be supported by its underlying handlers, due to error handling, see bug#57778. */ -#define HA_ONLINE_ADD_INDEX_NO_WRITES (1L << 0) /*add index w/lock*/ -#define HA_ONLINE_DROP_INDEX_NO_WRITES (1L << 1) /*drop index w/lock*/ -#define HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES (1L << 2) /*add unique w/lock*/ -#define HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES (1L << 3) /*drop uniq. w/lock*/ -#define HA_ONLINE_ADD_PK_INDEX_NO_WRITES (1L << 4) /*add prim. w/lock*/ -#define HA_ONLINE_DROP_PK_INDEX_NO_WRITES (1L << 5) /*drop prim. w/lock*/ +#define HA_INPLACE_ADD_INDEX_NO_READ_WRITE (1L << 0) +#define HA_INPLACE_DROP_INDEX_NO_READ_WRITE (1L << 1) +#define HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE (1L << 2) +#define HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE (1L << 3) +#define HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE (1L << 4) +#define HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE (1L << 5) /* - These are set if different kinds of indexes can be created on-line - (without a table lock). If a handler is capable of one or more of - these, it should also set the corresponding *_NO_WRITES bit(s). + These are set if different kinds of indexes can be created or dropped + in-place while still allowing concurrent reads (but not writes) of table + data. If a handler is capable of one or more of these, it should also set + the corresponding *_NO_READ_WRITE bit(s). */ -#define HA_ONLINE_ADD_INDEX (1L << 6) /*add index online*/ -#define HA_ONLINE_DROP_INDEX (1L << 7) /*drop index online*/ -#define HA_ONLINE_ADD_UNIQUE_INDEX (1L << 8) /*add unique online*/ -#define HA_ONLINE_DROP_UNIQUE_INDEX (1L << 9) /*drop uniq. online*/ -#define HA_ONLINE_ADD_PK_INDEX (1L << 10)/*add prim. online*/ -#define HA_ONLINE_DROP_PK_INDEX (1L << 11)/*drop prim. online*/ +#define HA_INPLACE_ADD_INDEX_NO_WRITE (1L << 6) +#define HA_INPLACE_DROP_INDEX_NO_WRITE (1L << 7) +#define HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE (1L << 8) +#define HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE (1L << 9) +#define HA_INPLACE_ADD_PK_INDEX_NO_WRITE (1L << 10) +#define HA_INPLACE_DROP_PK_INDEX_NO_WRITE (1L << 11) /* HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is supported at all. === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2010-11-19 07:26:09 +0000 +++ b/sql/sql_table.cc 2010-12-20 17:16:55 +0000 @@ -4735,7 +4735,7 @@ err: @details Checks if any index is being modified (present as both DROP INDEX and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling - online ALTER TABLE. + in-place ALTER TABLE. @param table The table being altered @param alter_info The ALTER TABLE structure @@ -4851,7 +4851,7 @@ mysql_compare_tables(TABLE *table, like to keep mysql_compare_tables() idempotent (not altering any of the arguments) we create a copy of alter_info here and pass it to mysql_prepare_create_table, then use the result - to evaluate possibility of fast ALTER TABLE, and then + to evaluate possibility of in-place ALTER TABLE, and then destroy the copy. */ Alter_info tmp_alter_info(*alter_info, thd->mem_root); @@ -4892,9 +4892,9 @@ mysql_compare_tables(TABLE *table, There was a bug prior to mysql-4.0.25. Number of null fields was calculated incorrectly. As a result frm and data files gets out of - sync after fast alter table. There is no way to determine by which + sync after in-place alter table. There is no way to determine by which mysql version (in 4.0 and 4.1 branches) table was created, thus we - disable fast alter table for all tables created by mysql versions + disable in-place alter table for all tables created by mysql versions prior to 5.0 branch. See BUG#6236. */ @@ -4917,7 +4917,7 @@ mysql_compare_tables(TABLE *table, } /* - Use transformed info to evaluate possibility of fast ALTER TABLE + Use transformed info to evaluate possibility of in-place ALTER TABLE but use the preserved field to persist modifications. */ new_field_it.init(alter_info->create_list); @@ -5197,7 +5197,7 @@ blob_length_by_type(enum_field_types typ semantic checks. This function is invoked when we know that we're going to - perform ALTER TABLE via a temporary table -- i.e. fast ALTER TABLE + perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE is not possible, perhaps because the ALTER statement contains instructions that require change in table data, not only in table definition or indexes. @@ -6092,7 +6092,7 @@ bool mysql_alter_table(THD *thd,char *ne } /* - If there are index changes only, try to do them online. "Index + If there are index changes only, try to do them in-place. "Index changes only" means also that the handler for the table does not change. The table is open and locked. The handler can be accessed. */ @@ -6100,8 +6100,8 @@ bool mysql_alter_table(THD *thd,char *ne { int pk_changed= 0; ulong alter_flags= 0; - ulong needed_online_flags= 0; - ulong needed_fast_flags= 0; + ulong needed_inplace_with_read_flags= 0; + ulong needed_inplace_flags= 0; KEY *key; uint *idx_p; uint *idx_end_p; @@ -6125,8 +6125,8 @@ bool mysql_alter_table(THD *thd,char *ne { DBUG_PRINT("info", ("Dropping primary key")); /* Primary key. */ - needed_online_flags|= HA_ONLINE_DROP_PK_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE; pk_changed++; candidate_key_count--; } @@ -6136,8 +6136,9 @@ bool mysql_alter_table(THD *thd,char *ne bool is_candidate_key= true; /* Non-primary unique key. */ - needed_online_flags|= HA_ONLINE_DROP_UNIQUE_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= + HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE; /* Check if all fields in key are declared @@ -6156,12 +6157,13 @@ bool mysql_alter_table(THD *thd,char *ne else { /* Non-unique key. */ - needed_online_flags|= HA_ONLINE_DROP_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_DROP_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE; } } no_pk= ((table->s->primary_key == MAX_KEY) || - (needed_online_flags & HA_ONLINE_DROP_PK_INDEX)); + (needed_inplace_with_read_flags & + HA_INPLACE_DROP_PK_INDEX_NO_WRITE)); /* Check added indexes. */ for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count; idx_p < idx_end_p; @@ -6199,57 +6201,59 @@ bool mysql_alter_table(THD *thd,char *ne { DBUG_PRINT("info", ("Adding primary key")); /* Primary key. */ - needed_online_flags|= HA_ONLINE_ADD_PK_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; pk_changed++; no_pk= false; } else { /* Non-primary unique key. */ - needed_online_flags|= HA_ONLINE_ADD_UNIQUE_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE; } } else { /* Non-unique key. */ - needed_online_flags|= HA_ONLINE_ADD_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_ADD_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_INDEX_NO_READ_WRITE; } } - if ((candidate_key_count > 0) && - (needed_online_flags & HA_ONLINE_DROP_PK_INDEX)) + if ((candidate_key_count > 0) && + (needed_inplace_with_read_flags & HA_INPLACE_DROP_PK_INDEX_NO_WRITE)) { /* Dropped primary key when there is some other unique not null key that should be converted to primary key */ - needed_online_flags|= HA_ONLINE_ADD_PK_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; + needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; pk_changed= 2; } - DBUG_PRINT("info", ("needed_online_flags: 0x%lx, needed_fast_flags: 0x%lx", - needed_online_flags, needed_fast_flags)); + DBUG_PRINT("info", + ("needed_inplace_with_read_flags: 0x%lx, needed_inplace_flags: 0x%lx", + needed_inplace_with_read_flags, needed_inplace_flags)); /* - Online or fast add/drop index is possible only if + In-place add/drop index is possible only if the primary key is not added and dropped in the same statement. Otherwise we have to recreate the table. need_copy_table is no-zero at this place. */ if ( pk_changed < 2 ) { - if ((alter_flags & needed_online_flags) == needed_online_flags) + if ((alter_flags & needed_inplace_with_read_flags) == + needed_inplace_with_read_flags) { - /* All required online flags are present. */ + /* All required in-place flags to allow concurrent reads are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; need_lock_for_indexes= FALSE; } - else if ((alter_flags & needed_fast_flags) == needed_fast_flags) + else if ((alter_flags & needed_inplace_flags) == needed_inplace_flags) { - /* All required fast flags are present. */ + /* All required in-place flags are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; } } @@ -6403,10 +6407,18 @@ bool mysql_alter_table(THD *thd,char *ne } else { - if (!table->s->tmp_table && + /* + Ensure that we will upgrade the metadata lock if + handler::enable/disable_indexes() will be called. + */ + if (alter_info->keys_onoff != LEAVE_AS_IS || + table->file->indexes_are_disabled()) + need_lock_for_indexes= true; + if (!table->s->tmp_table && need_lock_for_indexes && wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err_new_table_cleanup; thd_proc_info(thd, "manage keys"); + DEBUG_SYNC(thd, "alter_table_manage_keys"); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); error= trans_commit_stmt(thd); === modified file 'storage/innobase/handler/ha_innodb.cc' --- a/storage/innobase/handler/ha_innodb.cc 2010-12-17 11:11:34 +0000 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-20 17:16:55 +0000 @@ -2573,11 +2573,12 @@ innobase_alter_table_flags( /*=======================*/ uint flags) { - return(HA_ONLINE_ADD_INDEX_NO_WRITES - | HA_ONLINE_DROP_INDEX_NO_WRITES - | HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES - | HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES - | HA_ONLINE_ADD_PK_INDEX_NO_WRITES); + return(HA_INPLACE_ADD_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_INDEX_NO_WRITE + | HA_INPLACE_DROP_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE + | HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE); } /*****************************************************************//** --===============0616597363704944583== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jon.hauglid@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jon.hauglid@stripped # target_branch: file:///export/home/x/mysql-5.5-bugteam-bug42230/ # testament_sha1: a580da4a0b2a45ffbf4515b8acd018edfcb093f4 # timestamp: 2010-12-20 18:17:08 +0100 # source_branch: file:///export/home/x/mysql-5.1-bugteam/ # base_revision_id: bjorn.munch@stripped\ # ceqdtki1wgsuj0c7 # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWV2EvPwACdzfgH/we3f//3// /+C////1YBXmx8Jvec9sC3Y+9560koQFAWdvrr6p9HU+WO7Dq7d7feYKHvYC+wBX0A+5biKA3XuE oQJqYIT0ozJianqaD1HqaNDQABp6QAANAJQQAQmmo0AjTRCNAaMgNADTQDQAAShqaTQlNMamh6QP SHqGmjTQ0MgAAAAAAk0pI1GmFPTUmmQ8p6gzUaAA0DQ000DINAABFIkFP0ap6E0wIzQahow0ATJg QeobUGhoaMCRQECaZATE0GowjRU/FHpRspsRDIDPVPU0NqbJKTcFEESpBWxs7jsQ1ob2/u4pbn2h BVT9qktFmi12qhZXlVzfP3VWlcQJKe1t9V0PKUPpfOkfn3V267sOu68F9CzW1KMlsoyqsxlkQj+7 SDq4y1NSKW0ts983gGctk/Pq9kvGXm4SXzOYhOlFpRkmkvizcBu+VzTydqd+pcxmP96aSPXwyGFT C7TEjzh9Ff85GmgiFNeHQN6392nmLHw+fDd2+nydlXkpZVtKa6SaEz0d4EoNOFLUi66+Es2wgan+ G/fuJ7MeuvnS3QJJVdzEkleCKJgMYDbaBs5jINjEL1diOK7xdJWxB4dqDVAyQ1bpsQczTjgSr1SP 9zSYXL6heYu4TbGwbbQJsbD6/TPYeJ/JIOXq6P193do2aLnEdZRfeQHCFz9awwILP0iQxl3eYMMx XN611pdSF6zVlwt1Sz+2comKo0os0WMqgyzWa2V1CVmJXZLqNVoKUW7BVpV7PD41xFRecG2M5q5r BxTY15V3DF+KFcDpGgDwnQJ0EO+aDcceznPXx/eC4srLaKW0UUXgYc5hVXlkVHGEyBUQ6+rnu+xT ikdVS6TDHUMIxP5CF8URqBcpEtL+7rpbsL+8zJJkU4eCXN3oFEaXJTh/sc4v81u7BFRVjjFkcWJF N8PdRVMkLOUOxWKFVimGLUF+3kxXMbCnM3txOQ7FkP+MdLifQfGMKxFMctuJpUp3qhr9E46xhQ2U vkZva0tzq6diNKFwI8qOW1XG6rqMmN8rE5JTheQlK4fgGBXYcWZY6LEqcRhpljH3qJCRwdtIvqPj a/+PG/KC0TqQdbfCew6R3WObRE7Gt2vgqyz5crqlIM9Rhu/ox3r3Takw6VIP0bTCNWuwlqJiQyiq q2hySnM5kELzksuFK7eZlEpKaUmxSr77NK0yaTX+Zz9XLqH40rEdrWiS12BNCakmNZSe8BtOFYxM o6ttXQtBt4xgmIVo8EpvCGt7l4XTVo9NsvAXu3Xo8byGeZr+6Ppau0DyppbZZSzWShg2mlMgzkhz HT51yG2J7eLi7rdnv3ivVVXE8j4i7y5Vn+pen2Cthi6U0XM0cfZHYhfDk04sejcvuaVBtOG+Kg4J YDhRVURVX0ChOB6M5D1DTIsNtBa9jAX8rGzZyRebNlvq5HwK7hhdxUMw711w9/EkRYmTI/ViNxBs /phx6envt6tVarSg+ocLONOcey4uuqtEVrTrTmYvWlwexYmmgjPp9AOjmrse7hhejLyjp1YKvHbv oPrd+/EbRAeEMRB0Dfexi6Tc+ubcZdm9jNFlxVLxz5B7jveoBonYe44kiJY74pYmeBbSUikG8vBp M0IxcB65Hh9kJBvzOCjexgwF9XYaVJIL5GmK61wAYfuXq9DReKqw0yI3SFFcDk6pI6/Gbihs1zoL zJPSSaUhoxN6YquZxgmAQzzlMwaSJJZpiRYRXIaA3DkH1EzQcyRWV5UuIz7VTJGoxE1mPk0GFMVp IpS7hIGMBeIFFpLS8P6K8mZDJmELu1M2lxI8NNCQL5NLeMNTRPLVC3Vj2hZeViFLT0L8lmB5zpI2 jCDSR86hYeJp8Bx1h65EZU5LAuNbclG15JMp+J0EKiZanZVzr7vHVpi20UUv4ALVIQXgVPl5b2yE 6ECpxB6wB/RV0qoBYZsjQ/xsCS8bzCOQ+YPCW8cxcm+cHtFzBTXA0lDob0cC0fXEVhBHv7+rMR0x PzeGnPvZuIG5GSwOpERHRAraa+PnYchEZhWSBxB2d5ypbNg9ji7XaGMAdh3UsmEGmuBGhdR+cCl2 WBXBvS7Vzggr8X9EWC8DeS8I4GR3HvPkfkaVwprINQa4Z4yv9UqKQeMhyNtQn1ktZfKnHQGzrLj0 LrObzK8s+l9Iu45mhRJlpAJl7GeIzI6kUkkysjYkZOwdGOE+nTUm1sqi75d9p2NoO21BUCU2R/Uw 1/mTN4xUiV6DkDwyc1hJzc01SCl2YFFKk4aoy8ImY7jjnNG7ieTgx3p+QA98A+kfOOcpTKuaaF1l w261RJ/DzAN7xEqMilRbtT6pBkjEuTSODJxVPNgC79c62JkC5GczRkdRe0rGHIKT9kDoYLFxsGjJ 4kjUocpHX3nQzU6zXwOmiljqXdzTVaT4lGcnecDnXmSiQkwrAwDB0gkFg1OcEusmRAIHSGiwobih 3e6hyRxK6tHLIBlRzKN7PcaHBY2KMYyf9JodXUuy9XXfZoPFiEA2JkVLEhSRQUAgHWusk+NKA6YO Kc+eOexU5mzpyqehTV+oqLAzUCydQxqYHT3Hpa8cbrssE40m6MHPmvgm9CKSPSwQIHYwRwXxWCjw IEYzjOQRN4y4lTg6uUBXode1rmtNFlnUyrLGZ1JGobFKQCkxgeJDUsyQGyi6HYxQSLCg8WhyHJHo TLlzPia+R8RZjWeUPW2rsjNvftfpr1jUKEIQAnAByc0rkFLXkuAfOvzUGDH1Rgl70NInN5E89s6B hkLinFn+ATmCe1I9/xfIQ8suaooqrIeMmjLwQ3ck5jZRijKr6xLAusTduDPi86ZjZ2H1NKhY4wHp AGQdoLmqPaHYEkHEaPzP5/Q+Qrf+hXBUdBAoFkluIA2MHd3+IDKoNtVMjMSAN6LAipI1wON2m79g AcRFBIWJYGgSLAVrALEhakakwWbn4iYUCktjFVSE8ckl0yG+mNAnIaQCI/zJBESqi/EggF+Rp8xD YBoYkWiT38pMJnOM6DXLAJAlex6CByKifBZKJAMBSjgaAWwYApkSTDISlxJAhbwspwzziHJn5QDo glhMHACZxAhlLS4iIHNxn4NsxTmcofgkTEJXCVShvSGwESBCqNEVZ2G8oMQvxDSSGCFTbcFUBIAU iERItErgBgdEE1DZSgbp7QQTBuIJUmXGTJiAbDMjSMRQMbApUikVpNYlRGRaZDIg1UVBBaIIA0Ab AByLzgRC8KpjofmJbgVhiJUJ3HGwtjAKAhYIEsRmCQ0gVmQbjeZdV84uMGK3FuKtXGKYMYoo24XF pGN4ArOsR/JiRJoCROI2mNpjfG1IV9kMshERFWZMREEURFkQFVUVPZ7UhPF0+md4aoqoqIqq+/Pb s2JJJoaxKD4MxGaMMPCtNDXvi2hKJTBwLHyk0tZEPAAeQ6YsDBdgkc1IvOe7WcRtYD3zNJymR4Nw Ok4jUTBTw5nA272R2XDA6zhlpczVsEIpsAVN2ZmJWitAtZX7WppazhPA0FEMwaggihAfw/2MJmjK 0gwbD61819wKOmoiz+EiwHmljACPAQNRpYRTN1Ng0e/ektBr/AiHYYTKQROecnHyHKaILUCyTb94 zUTDY3eNFjKRCvMZc9KhbTDTNLRcDeqanxnMSAy+PCTA8xnaZUyNRmf8Fq6FSJcgkefrN5RdqDn5 EyIu9mBpNlR+0nF7FJCixB7R8SYqlP3EfJgccEJHlAPPHEiEkmtxLYZmG6RyPabz0GQJklZQtVVJ bzWbtW9hsaUA61/FBoXBZGPKKSkUgIXHiobtJf2UV64XbDtyE2wNXqgF1csKQc7CpGAxVkAvcQNQ hPi1saVFzOwzksWtTUmToCvz6mgQ26Ipa2nSYxYyNs8iNQURmLelm8kFAj2GMeWYl3MnYXA9XgeK ZwBcl6iuBfIroAColNRQlosJC1ntqzkogDQUvNyxLAxygktUWIYtyqJKNKfYH4tabcVLLUZBMKFt RGGvKdWo8VODJiKKzgNBt1II8z2AXUZjIawC2huRW4hy9Fsoj0L/B78ei2SCB3DZoBQqfQl6qWiH d1YujZo9S+JHHUNZhGFBovHiYIt0IteDEbEnk2JQlORAeyoMRZIDlbkqVKUVd8cYZRVFqaCUpgyM jYYnR3b32EA974b9xRM+9Jecoe+N5E9Rqw7RbRZHtKM2NQ2ZArEp4AoIiJZm8oJb2Kt8PtGCvMip getB43JC+zkZknk0oHvliaoZdz6ud23WW8al7rc7CUJQjK2U/bOAhakkuTv6HX5dpsADh2s4ozWC AgE1w+/HzO3LBy/KBnZuwX79xtm0Qo1GvUw9vdQLu4t8Upc00ExihamQAqdxh/UikiqwYyw/m0Ed U29sHUSJLzU9B/dqoNIJ3EZrpQOurGzH4q2b8FmVnFt2xIGUsQzDXf+ywIytRAV9o1JI0bVrIoIz AJHrglAtQuiLcjSbfZAR+1hAbSINQLV5C7joPYdD593E+R5Ez1K8iaS44G0vqiZ5r4QSyGatBgak Hen9BYefIUFqBiRshIIEgTuSAd1NxKBcgLoVgmlBocY4aeEf0usRUuMNBmVAiogrGM57cRAIIijX TGAKN4y0vJnoSStBDh1r38gkXJIXiexQErNJmqnaePsBi3m9Q+R8zWRVBJ0EvrPI1HIIqMT9EiiG qpF6QQXMiCP7BgPlRIUZsJbWQMogQCKYTQe3FRDScZx5mBEA8AESWHEgZnUq8buao9B8H2ewIhLt xlq8TH1oUUglGFVe3meL5QghtKqDZTYdNJkkxoWs94dDRyIkDAWthi0u0dvBBsUQTY17IBEkC+G1 ZtihdSc3UQu2sbY3JgvtnYHQNoXIVJ8DuWiqX7CREQTLr08M9oTewWRAXlOjmOzpOcVUYqKmwnYK oP0E+w4B1CC9hXQrddXJYnWxQ0r9J59R1JMW3czzwWSzAPULrTSF4mogGpdYdMpm1SQbz1+IBdpN xgWm/2nqJCmrWNnUjWFUEbIhIR6hCOSSAslj/f7uaJbzhJg2mJptMdrg0rAE4CbExTgQwwgUDOKR FxovkZeYIleFS4JsbP2EIeMEbNMN/5a0uCuFUqakZWkRMDcS3kQW0kcbJf9nC7Wndtj27CMLaQY4 IFa80ZqQd2ZwKVSqylgdzsv31bbhQqy2zSrjmrC+zVglC8KzUL1oPAu4HNYX5pSPQAv8sYYI0YyY wYhuXOyghkOnSSzAdxIUOoMgZRgdw7GswBaXpQsjpE1+kCdyoiEmlCiBjvaBRjIghJmZA7NrjFs2 5DN9/0nhzcHp+9uFNYIdaDHFjgYwSCI0GhEkoLPYZrrPZYgNaqCtWBrSU5ESKZgyI8wgIXRYKpY/ 9NOLSkwbQqsRwIBy8jp0+SCME2jNo8F8pOMaTZ4qCkhBkdyAiC9heS2pG5onQldkXzMp3CFi1l/W +CFKCgg/FIGE0MUmQA9+FGfHE4klk6r+In7Lr8MQqMGfVqgQZAoaSC/+AW4Sir98x7iAr1KZRNcN 6Dm/2w+Uio2wmXtG5fvGdlmNNiR94ByjRbPixMB9Sa71NL/C3WYKjNSqHeajA80lrELPQJfH3Bwf KZMEEdE2eG4B5nrlMwnHbojHLVALHa3TQagMzPZLztiCrwSqkfJaROsWWIIE1Aknb22cNBTilGla GMe4a8tRJZwTop4CGhq4nsSwoVREdNysL3EP6dsZolTUsNmkAjpR5htAJV6DRAOCokRVT7lmbXZ+ rC+SZazX4trYpQ0YAghMJAofkmbS5FQWEXuyB1ulM6acMWuKtMRMQ8wSzy1Ahi56TSBRR65ooKYE WvuVQdn3X7eS9BJXFMMFsA5/L1UWL3NGU/5iciIdffI7Jq9ozvJCo+Apqit3VQOBMXVrDqYbDaXZ j1YP3I+1tt6iuaYEYECJyWuFRvOUQuWoaNaDFS9CUrfv2JVEq5htpobJQUHq0HQdpJaa9aCRaaSg NOqUNZQ5N5g5N1EZLLGiPADI6z5X6KCr8wTiBUvaX9v84KKbTwE6Zu2wDHEvjreTDN3u87L/HMnz gKpUtJswJkgTiIIL600eDElFpDB/Yq5XT1aORSAz145kRogQRVNOq6K7x0AdjF1IQYCXUsJQeKd5 EvYEMNCRM5kluO89xvO0A2JKqe4kQDb2xQaf1/ACPaf6r46wQyZvXJGriUCTyPQiNaFXclIpxhmj mkRSmlkVMWNdERLeR5HXUZ8bTvE1rOy0b/PSlk3Rih9Yz9p2qRQIHrKTpUSX6Db2nwZAytwB904y p3pTgZ1QyEOIkQ64hrCatZQvVF95xOpRJnAyCdCczfsZiDvMVmgk3gzxgwQFVS4M88LzIboDy8KU GVEKjZwkXgDy+iKRkuS/HtReIybbGM3C//F3JFOFCQXYS8/A --===============0616597363704944583==--