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 /* Make sure we have enough stack to perform all the things we do in the
42 #define REDIS_THREAD_STACK_SIZE (1024*1024*4)
44 /* Initialize the background system, spawning the thread. */
50 pthread_mutex_init(&bio_mutex
,NULL
);
51 pthread_cond_init(&bio_condvar
,NULL
);
52 bio_jobs
= listCreate();
54 /* Set the stack size as by default it may be small in some system */
55 pthread_attr_init(&attr
);
56 pthread_attr_getstacksize(&attr
,&stacksize
);
57 if (!stacksize
) stacksize
= 1; /* The world is full of Solaris Fixes */
58 while (stacksize
< REDIS_THREAD_STACK_SIZE
) stacksize
*= 2;
59 pthread_attr_setstacksize(&attr
, stacksize
);
61 /* Ready to spawn our thread */
62 if (pthread_create(&thread
,&attr
,bioProcessBackgroundJobs
,NULL
) != 0) {
63 redisLog(REDIS_WARNING
,"Fatal: Can't initialize Background Jobs.");
68 void bioCreateBackgroundJob(int type
, void *data
) {
69 struct bio_job
*job
= zmalloc(sizeof(*job
));
73 pthread_mutex_lock(&bio_mutex
);
74 listAddNodeTail(bio_jobs
,job
);
75 pthread_cond_signal(&bio_condvar
);
76 pthread_mutex_unlock(&bio_mutex
);
79 void *bioProcessBackgroundJobs(void *arg
) {
83 pthread_detach(pthread_self());
84 pthread_mutex_lock(&bio_mutex
);
88 /* The loop always starts with the lock hold. */
89 if (listLength(bio_jobs
) == 0) {
90 pthread_cond_wait(&bio_condvar
,&bio_mutex
);
93 /* Pop the job from the queue. */
94 ln
= listFirst(bio_jobs
);
96 listDelNode(bio_jobs
,ln
);
97 /* It is now possible to unlock the background system as we know have
98 * a stand alone job structure to process.*/
99 pthread_mutex_unlock(&bio_mutex
);
101 /* Process the job accordingly to its type. */
102 if (job
->type
== REDIS_BIO_CLOSE_FILE
) {
103 printf("Closing file...\n");
104 close((long)job
->data
);
106 redisPanic("Wrong job type in bioProcessBackgroundJobs().");
110 /* Lock again before reiterating the loop, if there are no longer
111 * jobs to process we'll block again in pthread_cond_wait(). */
112 pthread_mutex_lock(&bio_mutex
);