4904de47d10e9e610d4194952a1381aa7b1ee69c
[idzebra-moved-to-github.git] / index / lockidx.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: lockidx.c,v $
7  * Revision 1.21  2002-02-20 17:30:01  adam
8  * Work on new API. Locking system re-implemented
9  *
10  * Revision 1.20  2000/10/16 20:16:00  adam
11  * Fixed problem with close of lock file for WIN32.
12  *
13  * Revision 1.19  2000/09/05 14:04:05  adam
14  * Updates for prefix 'yaz_' for YAZ log functions.
15  *
16  * Revision 1.18  2000/02/24 11:00:07  adam
17  * Fixed bug: indexer would run forever when lock dir was non-existant.
18  *
19  * Revision 1.17  1999/12/08 15:03:11  adam
20  * Implemented bf_reset.
21  *
22  * Revision 1.16  1999/02/02 14:50:57  adam
23  * Updated WIN32 code specific sections. Changed header.
24  *
25  * Revision 1.15  1998/02/17 10:31:33  adam
26  * Fixed bug in zebraIndexUnlock. On NT, the lock files wasn't removed.
27  *
28  * Revision 1.14  1998/01/12 15:04:08  adam
29  * The test option (-s) only uses read-lock (and not write lock).
30  *
31  * Revision 1.13  1997/09/29 09:08:36  adam
32  * Revised locking system to be thread safe for the server.
33  *
34  * Revision 1.12  1997/09/25 14:54:43  adam
35  * WIN32 files lock support.
36  *
37  * Revision 1.11  1997/09/17 12:19:15  adam
38  * Zebra version corresponds to YAZ version 1.4.
39  * Changed Zebra server so that it doesn't depend on global common_resource.
40  *
41  * Revision 1.10  1997/09/09 13:38:07  adam
42  * Partial port to WIN95/NT.
43  *
44  * Revision 1.9  1997/09/04 13:58:04  adam
45  * Added O_BINARY for open calls.
46  *
47  * Revision 1.8  1997/02/12 20:39:46  adam
48  * Implemented options -f <n> that limits the log to the first <n>
49  * records.
50  * Changed some log messages also.
51  *
52  * Revision 1.7  1996/10/29 14:08:13  adam
53  * Uses resource lockDir instead of lockPath.
54  *
55  * Revision 1.6  1996/03/26 16:01:13  adam
56  * New setting lockPath: directory of various lock files.
57  *
58  * Revision 1.5  1995/12/13  08:46:09  adam
59  * Locking uses F_WRLCK and F_RDLCK again!
60  *
61  * Revision 1.4  1995/12/12  16:00:57  adam
62  * System call sync(2) used after update/commit.
63  * Locking (based on fcntl) uses F_EXLCK and F_SHLCK instead of F_WRLCK
64  * and F_RDLCK.
65  *
66  * Revision 1.3  1995/12/11  11:43:29  adam
67  * Locking based on fcntl instead of flock.
68  * Setting commitEnable removed. Command line option -n can be used to
69  * prevent commit if commit setting is defined in the configuration file.
70  *
71  * Revision 1.2  1995/12/08  16:22:54  adam
72  * Work on update while servers are running. Three lock files introduced.
73  * The servers reload their registers when necessary, but they don't
74  * reestablish result sets yet.
75  *
76  * Revision 1.1  1995/12/07  17:38:47  adam
77  * Work locking mechanisms for concurrent updates/commit.
78  *
79  */
80 #include <stdio.h>
81 #include <assert.h>
82 #ifdef WIN32
83 #include <io.h>
84 #else
85 #include <unistd.h>
86 #endif
87 #include <fcntl.h>
88 #include <string.h>
89 #include <errno.h>
90
91 #include "index.h"
92 #include "zserver.h"
93
94 static ZebraLockHandle server_lock_main = NULL;
95 static ZebraLockHandle server_lock_cmt = NULL;
96 static ZebraLockHandle server_lock_org = NULL;
97
98 int zebraIndexWait (ZebraHandle zh, int commitPhase)
99 {
100     ZebraLockHandle h;
101
102     if (server_lock_cmt)
103         zebra_unlock (server_lock_cmt);
104     else
105     {
106         char path[1024];
107
108         zebra_lock_prefix (zh->service->res, path);
109         strcat (path, FNAME_COMMIT_LOCK);
110         server_lock_cmt = zebra_lock_create (path, 1);
111         if (!server_lock_cmt)
112         {
113             logf (LOG_WARN|LOG_ERRNO, "cannot create lock %s", path);
114             return -1;
115         }
116     }
117     if (server_lock_org)
118         zebra_unlock (server_lock_org);
119     else
120     {
121         char path[1024];
122
123         zebra_lock_prefix (zh->service->res, path);
124         strcat (path, FNAME_ORG_LOCK);
125         server_lock_org = zebra_lock_create (path, 1);
126         if (!server_lock_org)
127         {
128             logf (LOG_WARN|LOG_ERRNO, "cannot create lock %s", path);
129             return -1;
130         }
131     }
132     if (commitPhase)
133         h = server_lock_cmt;
134     else
135         h = server_lock_org;
136     if (zebra_lock_nb (h))
137     {
138 #ifndef WIN32
139         if (errno != EWOULDBLOCK)
140         {
141             logf (LOG_FATAL|LOG_ERRNO, "flock");
142             exit (1);
143         }
144 #endif
145         if (commitPhase)
146             logf (LOG_LOG, "Waiting for lock cmt");
147         else
148             logf (LOG_LOG, "Waiting for lock org");
149         if (zebra_lock (h) == -1)
150         {
151             logf (LOG_FATAL, "flock");
152             exit (1);
153         }
154     }
155     zebra_unlock (h);
156     return 0;
157 }
158
159
160 void zebraIndexLockMsg (ZebraHandle zh, const char *str)
161 {
162     char path[1024];
163     int l, r, fd;
164
165     assert (server_lock_main);
166     fd = zebra_lock_fd (server_lock_main);
167     lseek (fd, 0L, SEEK_SET);
168     l = strlen(str);
169     r = write (fd, str, l);
170     if (r != l)
171     {
172         logf (LOG_FATAL|LOG_ERRNO, "write lock file");
173         exit (1);
174     }
175     zebra_lock_prefix (zh->service->res, path);
176     strcat (path, FNAME_TOUCH_TIME);
177     fd = creat (path, 0666);
178     close (fd);
179 }
180
181 void zebraIndexUnlock (ZebraHandle zh)
182 {
183     char path[1024];
184     
185     zebra_lock_prefix (zh->service->res, path);
186     strcat (path, FNAME_MAIN_LOCK);
187 #ifdef WIN32
188     zebra_lock_destroy (server_lock_main);
189     if (unlink (path) && errno != ENOENT)
190         logf (LOG_WARN|LOG_ERRNO, "unlink %s failed", path);
191 #else
192     if (unlink (path) && errno != ENOENT)
193         logf (LOG_WARN|LOG_ERRNO, "unlink %s failed", path);
194     zebra_lock_destroy (server_lock_main);
195 #endif
196     server_lock_main = 0;
197 }
198
199 int zebraIndexLock (BFiles bfs, ZebraHandle zh, int commitNow,
200                     const char *rval)
201 {
202     char path[1024];
203     char buf[256];
204     int r;
205
206     if (server_lock_main)
207         return 0;
208
209     zebra_lock_prefix (zh->service->res, path);
210     strcat (path, FNAME_MAIN_LOCK);
211     while (1)
212     {
213         server_lock_main = zebra_lock_create (path, 2);
214         if (!server_lock_main)
215         {
216             server_lock_main = zebra_lock_create (path, 1);
217             if (!server_lock_main)
218             {
219                 logf (LOG_FATAL, "couldn't obtain indexer lock");
220                 exit (1);
221             }
222             if (zebra_lock_nb (server_lock_main) == -1)
223             {
224 #ifdef WIN32
225                 logf (LOG_LOG, "waiting for other index process");
226                 zebra_lock (server_lock_main);
227                 zebra_unlock (server_lock_main);
228                 zebra_lock_destroy (server_lock_main);
229                 continue;
230 #else
231                 if (errno == EWOULDBLOCK)
232                 {
233                     logf (LOG_LOG, "waiting for other index process");
234                     zebra_lock (server_lock_main);
235                     zebra_unlock (server_lock_main);
236                     zebra_lock_destroy (server_lock_main);
237                     continue;
238                 }
239                 else
240                 {
241                     logf (LOG_FATAL|LOG_ERRNO, "flock %s", path);
242                     exit (1);
243                 }
244 #endif
245             }
246             else
247             {
248                 int fd = zebra_lock_fd (server_lock_main);
249
250                 logf (LOG_WARN, "unlocked %s", path);
251                 r = read (fd, buf, 256);
252                 if (r == 0)
253                 {
254                     logf (LOG_WARN, "zero length %s", path);
255                     zebra_lock_destroy (server_lock_main);
256                     unlink (path);
257                     continue;
258                 }
259                 else if (r == -1)
260                 {
261                     logf (LOG_FATAL|LOG_ERRNO, "read %s", path);
262                     exit (1);
263                 }
264                 if (*buf == 'r')
265                 {
266                     logf (LOG_WARN, "previous transaction didn't"
267                           " reach commit");
268                     zebra_lock_destroy (server_lock_main);
269                     bf_commitClean (bfs, rval);
270                     unlink (path);
271                     continue;
272                 }
273                 else if (*buf == 'd')
274                 {
275                     logf (LOG_WARN, "commit file wan't deleted after commit");
276                     zebra_lock_destroy (server_lock_main);
277                     bf_commitClean (bfs, rval);
278                     unlink (path);
279                     continue;
280                 }                    
281                 else if (*buf == 'w')
282                 {
283                     logf (LOG_WARN,
284                           "The lock file indicates that your index is");
285                     logf (LOG_WARN, "inconsistent. Perhaps the indexer");
286                     logf (LOG_WARN, "terminated abnormally in the previous");
287                     logf (LOG_WARN, "run. You can try to proceed by");
288                     logf (LOG_WARN, "deleting the file %s", path);
289                     exit (1);
290                 }
291                 else if (*buf == 'c')
292                 {
293                     if (commitNow)
294                     {
295                         unlink (path);
296                         zebra_lock_destroy (server_lock_main);
297                         continue;
298                     }
299                     logf (LOG_FATAL, "previous transaction didn't"
300                           " finish commit. Commit now!");
301                     exit (1);
302                 }
303                 else 
304                 {
305                     logf (LOG_FATAL, "unknown id 0x%02x in %s", *buf,
306                           path);
307                     exit (1);
308                 }
309             }
310         }
311         else
312             break;
313     }
314     zebra_lock (server_lock_main);
315     return 0;
316 }
317