]>
Commit | Line | Data |
---|---|---|
02925dd9 | 1 | /* Background I/O service for Redis. |
2 | * | |
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. | |
8 | * | |
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 | |
13 | * implementation). | |
14 | * | |
15 | * DESIGN | |
16 | * ------ | |
17 | * | |
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. | |
22 | */ | |
23 | ||
24 | #include "redis.h" | |
25 | #include "bio.h" | |
26 | ||
27 | static pthread_mutex_t bio_mutex; | |
28 | static pthread_cond_t bio_condvar; | |
d47ded66 | 29 | static list *bio_jobs; |
02925dd9 | 30 | |
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. */ | |
33 | struct bio_job { | |
34 | int type; /* Job type, for instance BIO_JOB_CLOSE */ | |
35 | void *data; /* Job specific arguments pointer. */ | |
f81a5f54 | 36 | }; |
02925dd9 | 37 | |
38 | void *bioProcessBackgroundJobs(void *arg); | |
39 | ||
f81a5f54 | 40 | /* Make sure we have enough stack to perform all the things we do in the |
41 | * main thread. */ | |
42 | #define REDIS_THREAD_STACK_SIZE (1024*1024*4) | |
43 | ||
02925dd9 | 44 | /* Initialize the background system, spawning the thread. */ |
45 | void bioInit(void) { | |
46 | pthread_attr_t attr; | |
47 | pthread_t thread; | |
48 | size_t stacksize; | |
49 | ||
f81a5f54 | 50 | pthread_mutex_init(&bio_mutex,NULL); |
51 | pthread_cond_init(&bio_condvar,NULL); | |
02925dd9 | 52 | bio_jobs = listCreate(); |
53 | ||
54 | /* Set the stack size as by default it may be small in some system */ | |
55 | pthread_attr_init(&attr); | |
f81a5f54 | 56 | pthread_attr_getstacksize(&attr,&stacksize); |
02925dd9 | 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); | |
60 | ||
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."); | |
64 | exit(1); | |
65 | } | |
66 | } | |
67 | ||
68 | void bioCreateBackgroundJob(int type, void *data) { | |
69 | struct bio_job *job = zmalloc(sizeof(*job)); | |
70 | ||
71 | job->type = type; | |
72 | job->data = data; | |
73 | pthread_mutex_lock(&bio_mutex); | |
74 | listAddNodeTail(bio_jobs,job); | |
b7c739b0 | 75 | pthread_cond_signal(&bio_condvar); |
02925dd9 | 76 | pthread_mutex_unlock(&bio_mutex); |
77 | } | |
78 | ||
79 | void *bioProcessBackgroundJobs(void *arg) { | |
80 | struct bio_job *job; | |
f81a5f54 | 81 | REDIS_NOTUSED(arg); |
02925dd9 | 82 | |
83 | pthread_detach(pthread_self()); | |
84 | pthread_mutex_lock(&bio_mutex); | |
85 | while(1) { | |
86 | listNode *ln; | |
87 | ||
88 | /* The loop always starts with the lock hold. */ | |
8ea2dfd7 | 89 | if (listLength(bio_jobs) == 0) { |
02925dd9 | 90 | pthread_cond_wait(&bio_condvar,&bio_mutex); |
91 | continue; | |
92 | } | |
93 | /* Pop the job from the queue. */ | |
94 | ln = listFirst(bio_jobs); | |
95 | job = ln->value; | |
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); | |
100 | ||
101 | /* Process the job accordingly to its type. */ | |
102 | if (job->type == REDIS_BIO_CLOSE_FILE) { | |
103 | close((long)job->data); | |
104 | } else { | |
105 | redisPanic("Wrong job type in bioProcessBackgroundJobs()."); | |
106 | } | |
107 | zfree(job); | |
108 | ||
109 | /* Lock again before reiterating the loop, if there are no longer | |
110 | * jobs to process we'll block again in pthread_cond_wait(). */ | |
111 | pthread_mutex_lock(&bio_mutex); | |
112 | } | |
113 | } |