The default table type was changed from MyISAM to InnoDB on a few production servers. There were good reasons for doing this. Besides, what could possibly go wrong? Sometimes the status quo has value even when you can’t elaborate it.
MyISAM tables are created in several cases:
- CREATE TABLE (…) engine=MyISAM
- CREATE TABLE (…) ; // when the default storage engine is MyISAM
- implicit temporary tables created for ORDER BY and GROUP BY processing that are too large are converted from HEAP to MyISAM
What was the problem?
Users began reporting ER_LOCK_TABLE_FULL errors during long running CREATE TABLE AS SELECT statements. These statements did not specify the storage engine type and began using InnoDB. From reading the code, this error is raised when buf_LRU_buf_pool_running_out returns TRUE during an insert statement. It returns true when less than 25% of the memory allocated for innodb_buffer_pool_size is available for the buffer pool. Memory from this allocation can be used elsewhere including for lock structures.
I need to investigate this to determine whether the locks were used for the created table or the selected table. I don’t think the locks have to be used in either case. Locks on rows in the created table might not be needed because the table is not visible to other sessions until the CTAS statement completes (right?). In this case it was CREATE TEMPORARY TABLE … SELECT, so the table will never be visible to others. Share locks on rows in the selected table might have been taken to guarantee deterministic replay in replication. But this statement was run on a slave, so that should not be needed. I have dealt with this particular problem in the past.
When innodb_locks_unsafe_for_binlog is set in my.cnf, then share locks are not obtained on rows read from the selected table. InnoDB really should be clever enough to do this when the binlog is not open.
Lock structs appear are not allocated for the inserted table regardless of the value of innodb_locks_unsafe_for_binlog, so I have yet to determine the source of memory allocations from the buffer pool. The binary we use has behavior similar to innodb_locks_unsafe_for_binlog but based on whether or not the binlog is open.
Still a mystery
Memory is allocated from the buffer pool for:
- Buffer pool frames
- Row locks (trx->lock_heap) – but row locks should not be allocated for this statement given the fix or if innodb_locks_unsafe_for_binlog were used.
- Recovery (recv_sys->heap) – this looks like code that is only run during crash recovery when the server is started.
- Adaptive hash index (btr_search_sys->hash_index) – this should use no more than a fixed amount of memory as the number of pages to be indexed is fixed.
So, given the above, I don’t know what is using memory from the buffer pool. But I learned a bit more about InnoDB, so all is not lost.
Notes from 5.0.77
A call path to buf_LRU_get_free_block is:
mem_heap_create_block -> buf_frame_alloc -> buf_block_alloc
And mem_heap_create_block is called by (search for MEM_HEAP_BUFFER)
- mem_heap_create_func
- mem_heap_add_block
So the callers are:
- mem_heap_create_in_buffer
- used for trx->lock_heap, recv_sys->heap, ha_create
- used for ha_create
And ha_create is used for btr_search_sys->hash_index





