-
Sivert Sorumgard authored
reading table definition While retrieving a table definition when getting a table share, the LOCK_open mutex may be temporarily released. This allows a higher degree of concurrency when opening tables, and is needed for the new data dictionary where dictionary tables may need to be opened recursively. The following changes have been implemented: 1. A new TABLE_SHARE member m_open_in_progress is introduced to flag that a share is being initialized. Concurrent threads opening the same share must check this flag to see whether they must wait for the share to be initialized. 2. A condition variable COND_open is introduced for threads that need to wait for a share which is being opened. 3. We must wait for the share to be completely opened before returning from get_cached_table_share(). 4. There are loops iterating over all elements in the table definition cache. One loop is in close_cached_tables(), this is safe to keep as is because shares being opened are handled. The other loop is in list_open_tables(), here we found it better to ignore shares being opened to avoid situations where we would incorrectly present a table as being open (e.g. if the opening actually failed). 5. We must assert that the newly inserted share is actually present in the cache before returning from get_table_share(). 6. Shares being opened (m_open_in_progress == true) in close_cached_connection_tables() are skipped. Otherwise, due to the way TABLE_SHARE::connect_string is initialized in open_binary_frm(), there is a risk that connect_string.length is initialized while connect_string.str is not, hence making us read into uninitialized memory further down in close_cached_connection_tables(). Thus, in theory, there is a risk that shares are left in the cache that should really be closed (matching the submitted connection string), and this risk is already present since LOCK_open is unlocked before calling close_cached_connection_tables(). Now, close_cached_connection_tables() is called as the final step of DROP/ALTER SERVER, so its goal is to flush all tables which were open before DROP/ALTER SERVER started. Thus, if a share gets opened after close_cached_connection_tables() has started, the information about the server has already been updated, so the new table will use the new definition of the server. It might have been an issue, however if one thread started opening a federated table, read the old server definition into a share, and then a switch to another thread doing ALTER SERVER happened right before setting m_open_in_progress to false for the share. Because in this case ALTER SERVER would not flush the share opened by the first thread as it should have been. But luckily, server definitions affected by * SERVER statements are not read into TABLE_SHARE structures, but are read when we create the TABLE object in ha_federated::open(). This means that in close_cached_connection_tables(), ignoring shares that are in the process of being opened is safe, because such shares don't have TABLE objects associated with them yet.
Sivert Sorumgard authoredreading table definition While retrieving a table definition when getting a table share, the LOCK_open mutex may be temporarily released. This allows a higher degree of concurrency when opening tables, and is needed for the new data dictionary where dictionary tables may need to be opened recursively. The following changes have been implemented: 1. A new TABLE_SHARE member m_open_in_progress is introduced to flag that a share is being initialized. Concurrent threads opening the same share must check this flag to see whether they must wait for the share to be initialized. 2. A condition variable COND_open is introduced for threads that need to wait for a share which is being opened. 3. We must wait for the share to be completely opened before returning from get_cached_table_share(). 4. There are loops iterating over all elements in the table definition cache. One loop is in close_cached_tables(), this is safe to keep as is because shares being opened are handled. The other loop is in list_open_tables(), here we found it better to ignore shares being opened to avoid situations where we would incorrectly present a table as being open (e.g. if the opening actually failed). 5. We must assert that the newly inserted share is actually present in the cache before returning from get_table_share(). 6. Shares being opened (m_open_in_progress == true) in close_cached_connection_tables() are skipped. Otherwise, due to the way TABLE_SHARE::connect_string is initialized in open_binary_frm(), there is a risk that connect_string.length is initialized while connect_string.str is not, hence making us read into uninitialized memory further down in close_cached_connection_tables(). Thus, in theory, there is a risk that shares are left in the cache that should really be closed (matching the submitted connection string), and this risk is already present since LOCK_open is unlocked before calling close_cached_connection_tables(). Now, close_cached_connection_tables() is called as the final step of DROP/ALTER SERVER, so its goal is to flush all tables which were open before DROP/ALTER SERVER started. Thus, if a share gets opened after close_cached_connection_tables() has started, the information about the server has already been updated, so the new table will use the new definition of the server. It might have been an issue, however if one thread started opening a federated table, read the old server definition into a share, and then a switch to another thread doing ALTER SERVER happened right before setting m_open_in_progress to false for the share. Because in this case ALTER SERVER would not flush the share opened by the first thread as it should have been. But luckily, server definitions affected by * SERVER statements are not read into TABLE_SHARE structures, but are read when we create the TABLE object in ha_federated::open(). This means that in close_cached_connection_tables(), ignoring shares that are in the process of being opened is safe, because such shares don't have TABLE objects associated with them yet.
Loading