]>
Commit | Line | Data |
---|---|---|
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; | |
29 | list *bio_jobs; | |
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. */ | |
36 | } | |
37 | ||
38 | void *bioProcessBackgroundJobs(void *arg); | |
39 | ||
40 | /* Initialize the background system, spawning the thread. */ | |
41 | void bioInit(void) { | |
42 | pthread_attr_t attr; | |
43 | pthread_t thread; | |
44 | size_t stacksize; | |
45 | ||
46 | pthread_mutex_init(bio_mutex,NULL); | |
47 | pthread_cond_init(bio_condvar,NULL); | |
48 | bio_jobs = listCreate(); | |
49 | ||
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); | |
56 | ||
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."); | |
60 | exit(1); | |
61 | } | |
62 | } | |
63 | ||
64 | void bioCreateBackgroundJob(int type, void *data) { | |
65 | struct bio_job *job = zmalloc(sizeof(*job)); | |
66 | ||
67 | job->type = type; | |
68 | job->data = data; | |
69 | pthread_mutex_lock(&bio_mutex); | |
70 | listAddNodeTail(bio_jobs,job); | |
71 | pthread_mutex_unlock(&bio_mutex); | |
72 | } | |
73 | ||
74 | void *bioProcessBackgroundJobs(void *arg) { | |
75 | struct bio_job *job; | |
76 | ||
77 | pthread_detach(pthread_self()); | |
78 | pthread_mutex_lock(&bio_mutex); | |
79 | while(1) { | |
80 | listNode *ln; | |
81 | ||
82 | /* The loop always starts with the lock hold. */ | |
83 | if (listLength(server.io_newjobs) == 0) { | |
84 | pthread_cond_wait(&bio_condvar,&bio_mutex); | |
85 | continue; | |
86 | } | |
87 | /* Pop the job from the queue. */ | |
88 | ln = listFirst(bio_jobs); | |
89 | job = ln->value; | |
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); | |
94 | ||
95 | /* Process the job accordingly to its type. */ | |
96 | if (job->type == REDIS_BIO_CLOSE_FILE) { | |
97 | close((long)job->data); | |
98 | } else { | |
99 | redisPanic("Wrong job type in bioProcessBackgroundJobs()."); | |
100 | } | |
101 | zfree(job); | |
102 | ||
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); | |
106 | } | |
107 | } |