573fc00ca4833cca78c0d20d44d6f6a0a1d54b07
[exim.git] / src / src / enq.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2015 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* Functions concerned with serialization. */
9
10
11 #include "exim.h"
12
13
14
15
16 /*************************************************
17 *       Test for host or ETRN serialization      *
18 *************************************************/
19
20 /* This function is called when a host is listed for serialization of
21 connections. It is also called when ETRN is listed for serialization. We open
22 the misc database and look for a record, which implies an existing connection
23 or ETRN run. If increasing the count would take us past the given limit
24 value return FALSE.  If not, bump it and return TRUE.  If not found, create
25 one with value 1 and return TRUE.
26
27 Arguments:
28   key            string on which to serialize
29   lim            parallelism limit
30
31 Returns:         TRUE if OK to proceed; FALSE otherwise
32 */
33
34
35 BOOL
36 enq_start(uschar *key, unsigned lim)
37 {
38 dbdata_serialize *serial_record;
39 dbdata_serialize new_record;
40 open_db dbblock;
41 open_db *dbm_file;
42
43 DEBUG(D_transport) debug_printf("check serialized: %s\n", key);
44
45 /* Open and lock the waiting information database. The absence of O_CREAT is
46 deliberate; the dbfn_open() function - which is an Exim function - always tries
47 to create if it can't open a read/write file. It expects only O_RDWR or
48 O_RDONLY as its argument. */
49
50 if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE)))
51   return FALSE;
52
53 /* See if there is a record for this host or queue run; if there is, we cannot
54 proceed with the connection unless the record is very old. */
55
56 serial_record = dbfn_read(dbm_file, key);
57 if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
58   {
59   if (serial_record->count >= lim)
60     {
61     dbfn_close(dbm_file);
62     DEBUG(D_transport) debug_printf("outstanding serialization record for %s\n",
63       key);
64     return FALSE;
65     }
66   new_record.count = serial_record->count + 1;
67   }
68 else
69   new_record.count = 1;
70
71 /* We can proceed - insert a new record or update the old one. */
72
73 DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n",
74       key, new_record.count);
75 dbfn_write(dbm_file, key, &new_record, (int)sizeof(dbdata_serialize));
76 dbfn_close(dbm_file);
77 return TRUE;
78 }
79
80
81
82 /*************************************************
83 *              Release serialization             *
84 *************************************************/
85
86 /* This function is called when a serialized host's connection or serialized
87 ETRN queue run ends. We open the relevant database and delete its record.
88
89 Arguments:
90   key          the serialization key
91
92 Returns:       nothing
93 */
94
95 void
96 enq_end(uschar *key)
97 {
98 open_db dbblock;
99 open_db *dbm_file;
100 dbdata_serialize *serial_record;
101
102 DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
103
104 if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE))
105    || !(serial_record = dbfn_read(dbm_file, key))
106    )
107   return;
108 if (--serial_record->count > 0)
109   {
110   DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n",
111       key, serial_record->count);
112   dbfn_write(dbm_file, key, serial_record, (int)sizeof(dbdata_serialize));
113   }
114 else
115   {
116   DEBUG(D_transport) debug_printf("remove serialization record for %s\n", key);
117   dbfn_delete(dbm_file, key);
118   }
119 dbfn_close(dbm_file);
120 }
121
122 /* End of enq.c */