Monday, January 25, 2010

How InnoDB create thread: the basic data structure and procedure

How InnoDB create thread  in mysql-5.5.0-m2
  • basic data structures
  1. os_aio_read_array, os_aio_write_array, os_aio_ibuf_array, os_aio_log_array, os_aio_sync_array
/** The asynchronous i/o array structure */
 152 struct os_aio_array_struct{
 153         os_mutex_t      mutex;  /*!< the mutex protecting the aio array */
 154         os_event_t      not_full;
 155                                 /*!< The event which is set to the
 156                                 signaled state when there is space in
 157                                 the aio outside the ibuf segment */
 158         os_event_t      is_empty;
 159                                 /*!< The event which is set to the
 160                                 signaled state when there are no
 161                                 pending i/os in this array */
 162         ulint           n_slots;/*!< Total number of slots in the aio
 163                                 array.  This must be divisible by
 164                                 n_threads. */
 165         ulint           n_segments;
 166                                 /*!< Number of segments in the aio
 167                                 array of pending aio requests. A
 168                                 thread can wait separately for any one
 169                                 of the segments. */
 170         ulint           n_reserved;
 171                                 /*!< Number of reserved slots in the
 172                                 aio array outside the ibuf segment */
 173         os_aio_slot_t*  slots;  /*!< Pointer to the slots in the array */





  • the procedure
[the arrays]
os_aio_init(
3043         ulint   n_per_seg,      /*<! in: maximum number of pending aio
3044                                 operations allowed per segment */
3045         ulint   n_read_segs,    /*<! in: number of reader threads */
3046         ulint   n_write_segs,   /*<! in: number of writer threads */
3047         ulint   n_slots_sync)   /*<! in: number of slots in the sync aio
3048                                 array */

3072         os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg,
3073                                                 n_read_segs);

so each array contains (SRV_N_PENDING_IOS_PER_THREAD*srv_n_read_io_threads) slots.

os_aio_array_create(
2985         ulint   n,              /*!< in: maximum number of pending aio operations
2986                                 allowed; n must be divisible by n_segments */
2987         ulint   n_segments)     /*!< in: number of segments in the aio array */
2988 {
 
Malloc memory of the array and initialising the slots, this is the place we want!

[io handler thread for each slot in the array]
1. srv0start.c

/* Create i/o-handler threads: */
1336
1337         for (i = 0; i < srv_n_file_io_threads; i++) {
1338                 n[i] = i;
1339
1340                 os_thread_create(io_handler_thread, n + i, thread_ids + i);
1341         }

this function os_thread_create created threads as much as srv_n_file_io_threads, which equals to srv_n_read_threads + srv_n_write_threads +2/*log & buf*/

the first parameter io_handler_thread is the call back function and "n + i" is a parameter for io_handler_thread, means the thread will execute io_handler_thread as soon as it's created. n+i=i?Obviously ...
os_thread_create, this is the place we want!

2. srv0start.c
/********************************************************************//**
 472 I/o-handler thread function.
 473 @return OS_THREAD_DUMMY_RETURN */
 474 static
 475 os_thread_ret_t
 476 io_handler_thread(
 477 /*==============*/
 478         void*   arg)    /*!< in: pointer to the number of the segment in
 479                         the aio array */
 480 {
 481         ulint   segment;
 482         ulint   i;
 483
 484         segment = *((ulint*)arg);
 485

 490         for (i = 0;; i++) {
 491                 fil_aio_wait(segment);
 492
 493                 mutex_enter(&ios_mutex);
 494                 ios++;
 495                 mutex_exit(&ios_mutex);
 496         }
 497
 498         /* We count the number of threads in os_thread_exit(). A created
 499         thread should always use that to exit and not use return() to exit.
 500         The thread actually never comes here because it is exited in an
 501         os_event_wait(). */
 502
 503         os_thread_exit(NULL);
 504
 505         OS_THREAD_DUMMY_RETURN;
 506 }

segment = n+i = i .  e.g. segment range from 0-10 if srv_n_read_threads = srv_n_write_threads = 4.


3. fil0fil.c
/**********************************************************************//**
4400 Waits for an aio operation to complete. This function is used to write the
4401 handler for completed requests. The aio array of pending requests is divided
4402 into segments (see os0file.c for more info). The thread specifies which
4403 segment it wants to wait for. */
4404 UNIV_INTERN
4405 void
4406 fil_aio_wait(
4407 /*=========*/
4408         ulint   segment)        /*!< in: the number of the segment in the aio
4409                                 array to wait for */
4410 {

4428                 srv_set_io_thread_op_info(segment, "simulated aio handle");
4429
4430                 ret = os_aio_simulated_handle(segment, &fil_node,
4431                                               &message, &type);


4. os0file.c
/**********************************************************************//**
3780 Does simulated aio. This function should be called by an i/o-handler
3781 thread.
3782 @return TRUE if the aio operation succeeded */
3783 UNIV_INTERN    
3784 ibool
3785 os_aio_simulated_handle(
3786 /*====================*/
3787         ulint   global_segment, /*!< in: the number of the segment in the aio
3788                                 arrays to wait for; segment 0 is the ibuf
3789                                 i/o thread, segment 1 the log i/o thread,
3790                                 then follow the non-ibuf read threads, and as
3791                                 the last are the non-ibuf write threads */
3792         fil_node_t**message1,   /*!< out: the messages passed with the aio
3793                                 request; note that also in the case where
3794                                 the aio operation failed, these output
3795                                 parameters are valid and can be used to
3796                                 restart the operation, for example */
3797         void**  message2,
3798         ulint*  type)           /*!< out: OS_FILE_WRITE or ..._READ */

//get segment in specific array
3817         segment = os_aio_get_array_and_local_segment(&array, global_segment);


4013         /* Do the i/o with ordinary, synchronous i/o functions: */
4014         if (slot->type == OS_FILE_WRITE) {
4015                 ret = os_file_write(slot->name, slot->file, combined_buf,
4016                                     slot->offset, slot->offset_high,
4017                                     total_len);
4018         } else {
4019                 ret = os_file_read(slot->file, combined_buf,
4020                                    slot->offset, slot->offset_high, total_len);
4021         }

This function does the real i/o and deals many situation:
(1) pick the oldest io request if exists two simultaneously,
(2) pick the nearest io request if two are the same age,
(3) collect the consecutive io and execute them at one time.


Sincerely,

ZHOU Yuan <j0sf>

No comments:

Post a Comment