Mercurial > dovecot > core-2.2
comparison src/lib-storage/index/mbox/mbox-lock.c @ 9002:9d0037a997f4 HEAD
Initial commit for config rewrite.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 27 Jan 2009 18:21:53 -0500 |
parents | a9dd29e7dc4f |
children | 21d4363a3cf7 |
comparison
equal
deleted
inserted
replaced
8692:77c67307d316 | 9002:9d0037a997f4 |
---|---|
19 # include <sys/file.h> | 19 # include <sys/file.h> |
20 #endif | 20 #endif |
21 | 21 |
22 /* 0.1 .. 0.2msec */ | 22 /* 0.1 .. 0.2msec */ |
23 #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000) | 23 #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000) |
24 | |
25 /* lock methods to use in wanted order */ | |
26 #define DEFAULT_READ_LOCK_METHODS "fcntl" | |
27 #define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl" | |
28 /* lock timeout */ | |
29 #define MBOX_DEFAULT_LOCK_TIMEOUT (5*60) | |
30 /* assume stale dotlock if mbox file hasn't changed for n seconds */ | |
31 #define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120) | |
32 | 24 |
33 enum mbox_lock_type { | 25 enum mbox_lock_type { |
34 MBOX_LOCK_DOTLOCK, | 26 MBOX_LOCK_DOTLOCK, |
35 MBOX_LOCK_DOTLOCK_TRY, | 27 MBOX_LOCK_DOTLOCK_TRY, |
36 MBOX_LOCK_FCNTL, | 28 MBOX_LOCK_FCNTL, |
90 { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock }, | 82 { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock }, |
91 { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf }, | 83 { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf }, |
92 { 0, NULL, NULL } | 84 { 0, NULL, NULL } |
93 }; | 85 }; |
94 | 86 |
95 static bool lock_settings_initialized = FALSE; | |
96 static enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1]; | |
97 static enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1]; | |
98 static int lock_timeout, dotlock_change_timeout; | |
99 | |
100 static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type, | 87 static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type, |
101 time_t max_wait_time, int idx); | 88 time_t max_wait_time, int idx); |
102 static int mbox_unlock_files(struct mbox_lock_context *ctx); | 89 static int mbox_unlock_files(struct mbox_lock_context *ctx); |
103 | 90 |
104 static void mbox_read_lock_methods(const char *str, const char *env, | 91 static void mbox_read_lock_methods(const char *str, const char *env, |
131 locks[dest++] = type; | 118 locks[dest++] = type; |
132 } | 119 } |
133 locks[dest] = (enum mbox_lock_type)-1; | 120 locks[dest] = (enum mbox_lock_type)-1; |
134 } | 121 } |
135 | 122 |
136 static void mbox_init_lock_settings(void) | 123 static void mbox_init_lock_settings(struct mbox_storage *storage) |
137 { | 124 { |
138 const char *str; | 125 enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1]; |
126 enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1]; | |
139 int r, w; | 127 int r, w; |
140 | 128 |
141 str = getenv("MBOX_READ_LOCKS"); | 129 mbox_read_lock_methods(storage->set->mbox_read_locks, |
142 if (str == NULL) str = DEFAULT_READ_LOCK_METHODS; | 130 "mbox_read_locks", read_locks); |
143 mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks); | 131 mbox_read_lock_methods(storage->set->mbox_write_locks, |
144 | 132 "mbox_write_locks", write_locks); |
145 str = getenv("MBOX_WRITE_LOCKS"); | |
146 if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS; | |
147 mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks); | |
148 | 133 |
149 /* check that read/write list orders match. write_locks must contain | 134 /* check that read/write list orders match. write_locks must contain |
150 at least read_locks and possibly more. */ | 135 at least read_locks and possibly more. */ |
151 for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) { | 136 for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) { |
152 if (read_locks[r] == (enum mbox_lock_type)-1) | 137 if (read_locks[r] == (enum mbox_lock_type)-1) |
159 "Lock ordering must be the same with both, " | 144 "Lock ordering must be the same with both, " |
160 "and write locks must contain all read locks " | 145 "and write locks must contain all read locks " |
161 "(and possibly more)"); | 146 "(and possibly more)"); |
162 } | 147 } |
163 | 148 |
164 str = getenv("MBOX_LOCK_TIMEOUT"); | 149 storage->read_locks = p_new(storage->storage.pool, |
165 lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str); | 150 enum mbox_lock_type, MBOX_LOCK_COUNT+1); |
166 | 151 memcpy(storage->read_locks, read_locks, |
167 str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT"); | 152 sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1)); |
168 dotlock_change_timeout = str == NULL ? | 153 |
169 DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str); | 154 storage->write_locks = p_new(storage->storage.pool, |
170 | 155 enum mbox_lock_type, MBOX_LOCK_COUNT+1); |
171 lock_settings_initialized = TRUE; | 156 memcpy(storage->write_locks, write_locks, |
157 sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1)); | |
158 | |
159 storage->lock_settings_initialized = TRUE; | |
172 } | 160 } |
173 | 161 |
174 static int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type) | 162 static int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type) |
175 { | 163 { |
176 struct mbox_mailbox *mbox = ctx->mbox; | 164 struct mbox_mailbox *mbox = ctx->mbox; |
219 /* get next index we wish to try locking. it's the one after | 207 /* get next index we wish to try locking. it's the one after |
220 dotlocking. */ | 208 dotlocking. */ |
221 lock_types = ctx->lock_type == F_WRLCK || | 209 lock_types = ctx->lock_type == F_WRLCK || |
222 (ctx->lock_type == F_UNLCK && | 210 (ctx->lock_type == F_UNLCK && |
223 ctx->mbox->mbox_lock_type == F_WRLCK) ? | 211 ctx->mbox->mbox_lock_type == F_WRLCK) ? |
224 write_locks : read_locks; | 212 ctx->mbox->storage->write_locks : |
213 ctx->mbox->storage->read_locks; | |
225 | 214 |
226 for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) { | 215 for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) { |
227 if (lock_types[i] == MBOX_LOCK_DOTLOCK) | 216 if (lock_types[i] == MBOX_LOCK_DOTLOCK) |
228 break; | 217 break; |
229 } | 218 } |
368 return 1; | 357 return 1; |
369 | 358 |
370 ctx->dotlock_last_stale = -1; | 359 ctx->dotlock_last_stale = -1; |
371 | 360 |
372 memset(&set, 0, sizeof(set)); | 361 memset(&set, 0, sizeof(set)); |
373 set.use_excl_lock = (mbox->storage->storage.flags & | 362 set.use_excl_lock = mbox->storage->storage.set->dotlock_use_excl; |
374 MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0; | 363 set.nfs_flush = mbox->storage->storage.set->mail_nfs_storage; |
375 set.nfs_flush = (mbox->storage->storage.flags & | 364 set.timeout = mbox->storage->set->mbox_lock_timeout; |
376 MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0; | 365 set.stale_timeout = mbox->storage->set->mbox_dotlock_change_timeout; |
377 set.timeout = lock_timeout; | |
378 set.stale_timeout = dotlock_change_timeout; | |
379 set.callback = dotlock_callback; | 366 set.callback = dotlock_callback; |
380 set.context = ctx; | 367 set.context = ctx; |
381 | 368 |
382 ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock); | 369 ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock); |
383 if (ret < 0 && errno == EACCES && restrict_access_have_priv_gid() && | 370 if (ret < 0 && errno == EACCES && restrict_access_have_priv_gid() && |
586 | 573 |
587 ctx->lock_type = lock_type; | 574 ctx->lock_type = lock_type; |
588 | 575 |
589 lock_types = lock_type == F_WRLCK || | 576 lock_types = lock_type == F_WRLCK || |
590 (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ? | 577 (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ? |
591 write_locks : read_locks; | 578 ctx->mbox->storage->write_locks : |
579 ctx->mbox->storage->read_locks; | |
592 for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) { | 580 for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) { |
593 type = lock_types[i]; | 581 type = lock_types[i]; |
594 lock_status = lock_type != F_UNLCK; | 582 lock_status = lock_type != F_UNLCK; |
595 | 583 |
596 if (ctx->lock_status[type] == lock_status) | 584 if (ctx->lock_status[type] == lock_status) |
614 | 602 |
615 *fcntl_locked_r = FALSE; | 603 *fcntl_locked_r = FALSE; |
616 | 604 |
617 index_storage_lock_notify_reset(&mbox->ibox); | 605 index_storage_lock_notify_reset(&mbox->ibox); |
618 | 606 |
619 if (!lock_settings_initialized) | 607 if (!mbox->storage->lock_settings_initialized) |
620 mbox_init_lock_settings(); | 608 mbox_init_lock_settings(mbox->storage); |
621 | 609 |
622 if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) { | 610 if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) { |
623 /* read-only mbox stream. no need to lock. */ | 611 /* read-only mbox stream. no need to lock. */ |
624 i_assert(mbox->ibox.backend_readonly); | 612 i_assert(mbox->ibox.backend_readonly); |
625 mbox->mbox_lock_type = lock_type; | 613 mbox->mbox_lock_type = lock_type; |
626 return 1; | 614 return 1; |
627 } | 615 } |
628 | 616 |
629 max_wait_time = time(NULL) + lock_timeout; | 617 max_wait_time = time(NULL) + mbox->storage->set->mbox_lock_timeout; |
630 | 618 |
631 memset(&ctx, 0, sizeof(ctx)); | 619 memset(&ctx, 0, sizeof(ctx)); |
632 ctx.mbox = mbox; | 620 ctx.mbox = mbox; |
633 | 621 |
634 if (mbox->mbox_lock_type == F_WRLCK) { | 622 if (mbox->mbox_lock_type == F_WRLCK) { |
635 /* dropping to shared lock. first drop those that we | 623 /* dropping to shared lock. first drop those that we |
636 don't remove completely. */ | 624 don't remove completely. */ |
625 const enum mbox_lock_type *read_locks = | |
626 mbox->storage->read_locks; | |
627 | |
637 for (i = 0; i < MBOX_LOCK_COUNT; i++) | 628 for (i = 0; i < MBOX_LOCK_COUNT; i++) |
638 ctx.lock_status[i] = 1; | 629 ctx.lock_status[i] = 1; |
639 for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++) | 630 for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++) |
640 ctx.lock_status[read_locks[i]] = 0; | 631 ctx.lock_status[read_locks[i]] = 0; |
641 drop_locks = TRUE; | 632 drop_locks = TRUE; |
656 } | 647 } |
657 | 648 |
658 if (drop_locks) { | 649 if (drop_locks) { |
659 /* dropping to shared lock: drop the locks that are only | 650 /* dropping to shared lock: drop the locks that are only |
660 in write list */ | 651 in write list */ |
652 const enum mbox_lock_type *read_locks = | |
653 mbox->storage->read_locks; | |
654 const enum mbox_lock_type *write_locks = | |
655 mbox->storage->write_locks; | |
656 | |
661 memset(ctx.lock_status, 0, sizeof(ctx.lock_status)); | 657 memset(ctx.lock_status, 0, sizeof(ctx.lock_status)); |
662 for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++) | 658 for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++) |
663 ctx.lock_status[write_locks[i]] = 1; | 659 ctx.lock_status[write_locks[i]] = 1; |
664 for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++) | 660 for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++) |
665 ctx.lock_status[read_locks[i]] = 0; | 661 ctx.lock_status[read_locks[i]] = 0; |
689 if (mbox->mbox_lock_type == F_UNLCK) { | 685 if (mbox->mbox_lock_type == F_UNLCK) { |
690 ret = mbox_update_locking(mbox, lock_type, &fcntl_locked); | 686 ret = mbox_update_locking(mbox, lock_type, &fcntl_locked); |
691 if (ret <= 0) | 687 if (ret <= 0) |
692 return ret; | 688 return ret; |
693 | 689 |
694 if ((mbox->storage->storage.flags & | 690 if (mbox->storage->storage.set->mail_nfs_storage) { |
695 MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) { | |
696 if (fcntl_locked) { | 691 if (fcntl_locked) { |
697 nfs_flush_attr_cache_fd_locked(mbox->path, | 692 nfs_flush_attr_cache_fd_locked(mbox->path, |
698 mbox->mbox_fd); | 693 mbox->mbox_fd); |
699 nfs_flush_read_cache_locked(mbox->path, | 694 nfs_flush_read_cache_locked(mbox->path, |
700 mbox->mbox_fd); | 695 mbox->mbox_fd); |