Redis source code analysis (19th) --- bio background I/O service implementation

Source: Internet
Author: User

There is also a background service concept in the redis system. The background service and background thread mainly act as background I/O service in redis. With the support of background threads, the execution efficiency of the system will inevitably be improved differently. In the redis code, the file describing this function is bio. C. Also, I would like to take this opportunity to learn how the multi-thread programming in the C language is. Let's take a look at the working format of the background job in redis;

/* Background I/O service for redis. ** background I/o Service * this file implements operations that we need to perform in the background. * Currently there is only a single operation, that is a background close (2) * system call. this is needed as when the process is the last owner of a * Reference to a file closing it means unlinking it, and the deletion of the * file is slow, blocking the server. ** in the future we'll either continue implementing new things we need or * We'll switch to libeio. however there are probably long term uses for this * file as we may want to put here redis specific background tasks (for instance * it is not impossible that we'll need a Non Blocking flushdb/ flushall * Implementation ). ** design ** ------ ** the design is trivial, we have a structure representing a job to perform * and a different thread and Job Queue for every job type. * Every thread wait for new jobs in its queue, and process every job * sequentially. ** jobs of the same type are guaranteed to be processed from the least * recently inserted to the most recently inserted (older jobs processed * first ). ** currently there is no way for the creator of the job to be notified about * the completion of the operation, this will only be added when/if needed. ** the author defines a struct to represent a job. Each thread is waiting to obtain a job from the corresponding job type work queue. Each job is arranged in a * sorted * sequence by time *----------------------------------------------------------------------------
There are two types of background I/O types in total:

/* Background job Opcodes * // * defines two types of background work */# define redis_bio_close_file 0/* Deferred close (2) syscall. close the file */# define redis_bio_aof_fsync 1/* Deferred aof fsync. aof file synchronization * // * The total number of bio background operation types is 2 */# define redis_bio_num_ops 2
One is the aof file synchronization operation, and the aof is the abbreviation of "APPEND only file". It records the write operation of each data change for data recovery. Another one I don't seem to have encountered. Close file means closing files asynchronously.

Static pthread_t bio_threads [redis_bio_num_ops];/* defines the bio thread group variable */static pthread_mutex_t bio_mutex [redis_bio_num_ops];/* mutex variable corresponding to the thread, used for synchronization operations */static pthread_cond_t bio_condvar [redis_bio_num_ops]; static list * bio_jobs [redis_bio_num_ops]; /* each job type is a list * // * the following array is used to hold the number of pending jobs for every * op type. this allows us to export the biopendingjobsoftype () API that is * useful when the main thread wants to perform some operation that may involve * objects shared with the background thread. the main thread will just wait * That there are no longer jobs of this type to be executed before encounter * the sensible operation. this data is also useful for reporting. */static unsigned long bio_pending [redis_bio_num_ops];/* number of jobs of this type waiting for execution * // * This structure represents a background job. it is only used locally to this * file as the API does not expose the internals at all. * // * Background job struct */struct bio_job {// The Job Creation Time time_t time;/* time at which the job was created. * // * job specific arguments pointers. if we need to pass more than three * arguments we can just pass a pointer to a structure or alike. * // * job specific parameter pointer */void * arg1, * arg2, * arg3 ;};
Some variables are declared above, including the bio_threads thread array, two in total, and the bio_jobs list array, which stores jobs of each type. The following describes the main methods:

/* Exported API */void bioinit (void);/* background I/O initialization operation */void biocreatebackgroundjob (INT type, void * arg1, void * arg2, void * arg3);/* Create a background job and initialize it using the input three parameters */unsigned long biopendingjobsoftype (INT type ); /* return the number of jobs of the type waiting for execution */void biowaitpendingjobsystemic (INT type, unsigned long num ); /* return the number of types of jobs waiting for execution */time_t bioolderjoboftype (INT type); void biokillthreads (void);/* Kill all background threads */
First, check the initialization operation;

/* Initialize the background system, spawning the thread. * // * background I/O initialization operation */void bioinit (void) {pthread_attr_t ATTR; pthread_t thread; size_t stacksize; Int J; /* initialization of State vars and objects */For (j = 0; j <redis_bio_num_ops; j ++) {pthread_mutex_init (& bio_mutex [J], null ); pthread_cond_init (& bio_condvar [J], null); // create a list for each job type bio_jobs [J] = listcreate (); bio_pending [J] = 0;}/* set the stack size as by default it may be small in some system * // set the thread stack space pthread_attr_init (& ATTR); pthread_attr_getstacksize (& ATTR, & stacksize); If (! Stacksize) stacksize = 1;/* The world is full of Solaris fixes */while (stacksize <redis_thread_stack_size) stacksize * = 2; pthread_attr_setstacksize (& ATTR, stacksize ); /* ready to spawn our threads. we use the single argument the thread * function accepts in order to pass the job ID the thread is * responsible. */For (j = 0; j <redis_bio_num_ops; j ++) {void * Arg = (void *) (unsigned long) j; // Create two threads to run the corresponding job if (pthread_create (& Thread, & ATTR, bioprocessbackgroundjobs, ARG )! = 0) {redislog (redis_warning, "Fatal: Can't initialize background jobs. "); exit (1) ;}// assign a value to the corresponding thread bio_threads [J] = thread ;}}
That is to say, after the above operations are completed, two threads are run in the bio_threads thread, and the corresponding Waiting Jo is retrieved from the respective job list;

/* Create a background job and initialize the job using the input three parameters */void biocreatebackgroundjob (INT type, void * arg1, void * arg2, void * arg3) {struct bio_job * job = zmalloc (sizeof (* job); job-> time = Time (null); job-> arg1 = arg1; job-> arg2 = arg2; job-> arg3 = arg3; pthread_mutex_lock (& bio_mutex [type]); // Add the corresponding job type list listaddnodetail (bio_jobs [type], job ); // The number of waiting jobs increases by 1 bio_pending [type] ++; pthread_cond_signal (& bio_condvar [type]); pthread_mutex_unlock (& bio_mutex [type]);}
Simple creation of background job operations, the above uses the mutex variable to achieve thread synchronization operations, to ensure thread security. Next, let's take a look at the most important implementation of the background job (some code is omitted ):

/* Run the background job. Which type */void * bioprocessbackgroundjobs (void * Arg ){...... while (1) {listnode * ln;/* The loop always starts with the lock hold. */If (listlength (bio_jobs [type]) = 0) {pthread_cond_wait (& bio_condvar [type], & bio_mutex [type]); continue ;} /* Pop the job from the queue. * /// retrieve the First Job Ln = listfirst (bio_jobs [type]) from the work list; job = ln-> value; /* it is now possible to unlock the background system as we know have * a stand alone job structure to process. */pthread_mutex_unlock (& bio_mutex [type]);/* process the job accordingly to its type. * // execute the specific job if (type = redis_bio_close_file) {close (long) Job-> arg1);} else if (type = redis_bio_aof_fsync) {aof_fsync (long) Job-> arg1);} else {redispanic ("wrong job type in bioprocessbackgroundjobs (). ");} zfree (job);/* lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait (). */pthread_mutex_lock (& bio_mutex [type]); listdelnode (bio_jobs [type], LN); bio_pending [type] --;}
While loop, extract one from the queue and execute one operation. Of course, if you want to immediately stop all background threads, You can execute the following method and call
Pthread_cancel:

/* Kill the running bio threads in an unclean way. this function shoshould be * used only when it's critical to stop the threads for some reason. * Currently redis does this only on crash (for instance on SIGSEGV) in order * to perform a fast memory check without other threads messing with memory. * // * Kill all backend threads */void biokillthreads (void) {int err, J; For (j = 0; j <redis_bio_num_ops; j ++) {// call PTH Read_cancel method kill the current background thread if (pthread_cancel (bio_threads [J]) = 0) {If (ERR = pthread_join (bio_threads [J], null ))! = 0) {redislog (redis_warning, "Bio thread for job type # % d can be joined: % s", J, strerror (ERR);} else {redislog (redis_warning, "Bio thread for job type # % d terminated", j );}}}}

Redis source code analysis (19th) --- bio background I/O service implementation

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.