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);