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