1 #ifndef MAIL_DUPLICATE_H
2 #define MAIL_DUPLICATE_H
3 
4 struct mail_duplicate_db;
5 
6 enum mail_duplicate_check_result {
7 	/* The ID exists. The ID is not locked. */
8 	MAIL_DUPLICATE_CHECK_RESULT_EXISTS,
9 	/* The ID doesn't exist yet. The ID gets locked. */
10 	MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND,
11 	/* Internal I/O error (e.g. permission error) */
12 	MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR,
13 	/* Locking timed out. */
14 	MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT,
15 	/* Too many locks held. */
16 	MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS,
17 	/* Locking detected a deadlock. The caller should rollback the
18 	   transaction to release all locks, do a short random sleep, retry
19 	   and hope that the next attempt succeeds. */
20 	MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK,
21 };
22 
23 #define MAIL_DUPLICATE_DEFAULT_KEEP (3600 * 24)
24 
25 struct mail_duplicate_transaction *
26 mail_duplicate_transaction_begin(struct mail_duplicate_db *db);
27 void mail_duplicate_transaction_rollback(
28 	struct mail_duplicate_transaction **_trans);
29 void mail_duplicate_transaction_commit(
30 	struct mail_duplicate_transaction **_trans);
31 
32 /* Check if id exists in the duplicate database. If not, lock the id. Any
33    further checks for the same id in other processes will block until the first
34    one's transaction is finished. Because checks can be done in different order
35    by different processes, this can result in a deadlock. The caller should
36    handle it by rolling back the transaction and retrying. */
37 enum mail_duplicate_check_result
38 mail_duplicate_check(struct mail_duplicate_transaction *trans,
39 		     const void *id, size_t id_size, const char *user);
40 /* Add id to the duplicate database. The writing isn't done until transaction
41    is committed. There's no locking done by this call. If locking is needed,
42    mail_duplicate_check() should be called first. */
43 void mail_duplicate_mark(struct mail_duplicate_transaction *trans,
44 			 const void *id, size_t id_size,
45 			 const char *user, time_t timestamp);
46 
47 struct mail_duplicate_db *
48 mail_duplicate_db_init(struct mail_user *user, const char *name);
49 void mail_duplicate_db_deinit(struct mail_duplicate_db **db);
50 
51 #endif
52