1 /* Background I/O service for Redis. 
   3  * This file implements operations that we need to perform in the background. 
   4  * Currently there is only a single operation, that is a background close(2) 
   5  * system call. This is needed as when the process is the last owner of a 
   6  * reference to a file closing it means unlinking it, and the deletion of the 
   7  * file is slow, blocking the server. 
   9  * In the future we'll either continue implementing new things we need or 
  10  * we'll switch to libeio. However there are probably long term uses for this 
  11  * file as we may want to put here Redis specific background tasks (for instance 
  12  * it is not impossible that we'll need a non blocking FLUSHDB/FLUSHALL 
  18  * The design is trivial, we have a structure representing a job to perform 
  19  * and a single thread performing all the I/O operations in the queue. 
  20  * Currently there is no way for the creator of the job to be notified about 
  21  * the completion of the operation, this will only be added when/if needed. 
  27 static pthread_mutex_t bio_mutex
; 
  28 static pthread_cond_t bio_condvar
; 
  31 /* This structure represents a background Job. It is only used locally to this 
  32  * file as the API deos not expose the internals at all. */ 
  34     int type
;       /* Job type, for instance BIO_JOB_CLOSE */ 
  35     void *data
;     /* Job specific arguments pointer. */ 
  38 void *bioProcessBackgroundJobs(void *arg
); 
  40 /* Initialize the background system, spawning the thread. */ 
  46     pthread_mutex_init(bio_mutex
,NULL
); 
  47     pthread_cond_init(bio_condvar
,NULL
); 
  48     bio_jobs 
= listCreate(); 
  50     /* Set the stack size as by default it may be small in some system */ 
  51     pthread_attr_init(&attr
); 
  52     pthread_attr_getstacksize(&attr
); 
  53     if (!stacksize
) stacksize 
= 1; /* The world is full of Solaris Fixes */ 
  54     while (stacksize 
< REDIS_THREAD_STACK_SIZE
) stacksize 
*= 2; 
  55     pthread_attr_setstacksize(&attr
, stacksize
); 
  57     /* Ready to spawn our thread */ 
  58     if (pthread_create(&thread
,&attr
,bioProcessBackgroundJobs
,NULL
) != 0) { 
  59         redisLog(REDIS_WARNING
,"Fatal: Can't initialize Background Jobs."); 
  64 void bioCreateBackgroundJob(int type
, void *data
) { 
  65     struct bio_job 
*job 
= zmalloc(sizeof(*job
)); 
  69     pthread_mutex_lock(&bio_mutex
); 
  70     listAddNodeTail(bio_jobs
,job
); 
  71     pthread_mutex_unlock(&bio_mutex
); 
  74 void *bioProcessBackgroundJobs(void *arg
) { 
  77     pthread_detach(pthread_self()); 
  78     pthread_mutex_lock(&bio_mutex
); 
  82         /* The loop always starts with the lock hold. */ 
  83         if (listLength(server
.io_newjobs
) == 0) { 
  84             pthread_cond_wait(&bio_condvar
,&bio_mutex
); 
  87         /* Pop the job from the queue. */ 
  88         ln 
= listFirst(bio_jobs
); 
  90         listDelNode(bio_jobs
,ln
); 
  91         /* It is now possible to unlock the background system as we know have 
  92          * a stand alone job structure to process.*/ 
  93         pthread_mutex_unlock(&bio_mutex
); 
  95         /* Process the job accordingly to its type. */ 
  96         if (job
->type 
== REDIS_BIO_CLOSE_FILE
) { 
  97             close((long)job
->data
); 
  99             redisPanic("Wrong job type in bioProcessBackgroundJobs()."); 
 103         /* Lock again before reiterating the loop, if there are no longer 
 104          * jobs to process we'll block again in pthread_cond_wait(). */ 
 105         pthread_mutex_lock(&bio_mutex
);