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