root/jlog_io.c

Revision e1fb6fb899c091c26f05a374ed27e067d4d5a3be, 7.3 kB (checked in by Theo Schlossnagle <theo.schlossnagle@circonus.com>, 1 month ago)

Build on darwin and build clean

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2005-2008, Message Systems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *    * Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *    * Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials provided
14  *      with the distribution.
15  *    * Neither the name Message Systems, Inc. nor the names
16  *      of its contributors may be used to endorse or promote products
17  *      derived from this software without specific prior written
18  *      permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34  * We want the single unix spec, so this define is needed on
35  * the identity crisis that is Linux. pread()/pwrite()
36  */
37 #define _XOPEN_SOURCE 500
38
39 #include "jlog_config.h"
40 #include "jlog_hash.h"
41 #include "jlog_io.h"
42 #include <assert.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <pthread.h>
46 #include <sys/mman.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49
50 static pthread_mutex_t jlog_files_lock = PTHREAD_MUTEX_INITIALIZER;
51 static jlog_hash_table jlog_files = JLOG_HASH_EMPTY;
52
53 typedef struct {
54   dev_t st_dev;
55   ino_t st_ino;
56 } jlog_file_id;
57
58 struct _jlog_file {
59   jlog_file_id id;
60   int fd;
61   int refcnt;
62   int locked;
63   pthread_mutex_t lock;
64   uint8_t multi_process;
65 };
66
67 jlog_file *jlog_file_open(const char *path, int flags, int mode, int multi_process)
68 {
69   struct stat sb;
70   jlog_file_id id;
71   jlog_file *f = NULL;
72   union {
73     jlog_file *f;
74     void *vptr;
75   } pun;
76   int fd, realflags = O_RDWR;
77
78   if (flags & O_CREAT) realflags |= O_CREAT;
79   if (flags & O_EXCL) realflags |= O_EXCL;
80
81   if (pthread_mutex_lock(&jlog_files_lock) != 0) return NULL;
82
83   if (stat(path, &sb) == 0) {
84     if (!S_ISREG(sb.st_mode)) goto out;
85     memset(&id, 0, sizeof(id));
86     id.st_dev = sb.st_dev;
87     id.st_ino = sb.st_ino;
88     if (jlog_hash_retrieve(&jlog_files, (void *)&id, sizeof(jlog_file_id),
89                            &pun.vptr))
90     {
91       if (!(flags & O_EXCL)) {
92         f = pun.f;
93         f->refcnt++;
94       }
95       goto out;
96     }
97   }
98
99   if ((fd = open(path, realflags, mode)) == -1) goto out;
100   if (fstat(fd, &sb) != 0) {
101     while (close(fd) == -1 && errno == EINTR) ;
102     goto out;
103   }
104   id.st_dev = sb.st_dev;
105   id.st_ino = sb.st_ino;
106   if (!(f = malloc(sizeof(jlog_file)))) {
107     while (close(fd) == -1 && errno == EINTR) ;
108     goto out;
109   }
110   memset(f, 0, sizeof(jlog_file));
111   f->id = id;
112   f->fd = fd;
113   f->refcnt = 1;
114   f->locked = 0;
115   f->multi_process = multi_process;
116   pthread_mutex_init(&(f->lock), NULL);
117   if (!jlog_hash_store(&jlog_files, (void *)&f->id, sizeof(jlog_file_id), f)) {
118     while (close(f->fd) == -1 && errno == EINTR) ;
119     free(f);
120     f = NULL;
121   }
122 out:
123   pthread_mutex_unlock(&jlog_files_lock);
124   return f;
125 }
126
127 int jlog_file_close(jlog_file *f)
128 {
129   if (pthread_mutex_lock(&jlog_files_lock) != 0) return 0;
130   if (--f->refcnt == 0) {
131     assert(jlog_hash_delete(&jlog_files, (void *)&f->id, sizeof(jlog_file_id),
132                             NULL, NULL));
133     while (close(f->fd) == -1 && errno == EINTR) ;
134     pthread_mutex_destroy(&(f->lock));
135     free(f);
136   }
137   pthread_mutex_unlock(&jlog_files_lock); 
138   return 1;
139 }
140
141 int jlog_file_lock(jlog_file *f)
142 {
143   struct flock fl;
144   int frv;
145
146   if (pthread_mutex_lock(&(f->lock)) != 0) return 0;
147
148   if (f->multi_process != 0) {
149     memset(&fl, 0, sizeof(fl));
150     fl.l_type = F_WRLCK;
151     fl.l_whence = SEEK_SET;
152     fl.l_start = 0;
153     fl.l_len = 0;
154
155     while ((frv = fcntl(f->fd, F_SETLKW, &fl)) == -1 && (errno == EINTR || errno == EAGAIN)) ;
156     if (frv != 0) {
157       int save = errno;
158       pthread_mutex_unlock(&(f->lock));
159       errno = save;
160       return 0;
161     }
162   }
163
164   f->locked = 1;
165   return 1;
166 }
167
168 int jlog_file_unlock(jlog_file *f)
169 {
170   struct flock fl;
171   int frv;
172
173   if (!f->locked) return 0;
174
175   if (f->multi_process != 0) {
176     memset(&fl, 0, sizeof(fl));
177     fl.l_type = F_UNLCK;
178     fl.l_whence = SEEK_SET;
179     fl.l_start = 0;
180     fl.l_len = 0;
181
182     while ((frv = fcntl(f->fd, F_SETLKW, &fl)) == -1 && (errno == EINTR || errno == EAGAIN)) ;
183     if (frv != 0) return 0;
184     f->locked = 0;
185   }
186   pthread_mutex_unlock(&(f->lock));
187   return 1;
188 }
189
190 int jlog_file_pread(jlog_file *f, void *buf, size_t nbyte, off_t offset)
191 {
192   while (nbyte > 0) {
193     ssize_t rv = pread(f->fd, buf, nbyte, offset);
194     if (rv == -1 && errno == EINTR) continue;
195     if (rv <= 0) return 0;
196     nbyte -= rv;
197     offset += rv;
198   }
199   return 1;
200 }
201
202 int jlog_file_pwrite(jlog_file *f, const void *buf, size_t nbyte, off_t offset)
203 {
204   while (nbyte > 0) {
205     ssize_t rv = pwrite(f->fd, buf, nbyte, offset);
206     if (rv == -1 && errno == EINTR) continue;
207     if (rv <= 0) return 0;
208     nbyte -= rv;
209     offset += rv;
210   }
211   return 1;
212 }
213
214 int jlog_file_pwritev(jlog_file *f, const struct iovec *vecs, int iov_count, off_t offset)
215 {
216   ssize_t rv = 0;
217   while (1) {
218 #ifdef HAVE_PWRITEV
219     rv = pwritev(f->fd, vecs, iov_count, offset);
220 #else
221     if(lseek(f->fd, offset, SEEK_SET) < 0) return 0;
222     rv = writev(f->fd, vecs, iov_count);
223 #endif
224     if (rv == -1 && errno == EINTR) continue;
225     if (rv <= 0) return 0;
226     break;
227   }
228   return 1;
229 }
230
231 int jlog_file_sync(jlog_file *f)
232 {
233   int rv;
234
235 #ifdef HAVE_FDATASYNC
236   while((rv = fdatasync(f->fd)) == -1 && errno == EINTR) ;
237 #else
238   while((rv = fsync(f->fd)) == -1 && errno == EINTR) ;
239 #endif
240   if (rv == 0) return 1;
241   return 0;
242 }
243
244 int jlog_file_map_rdwr(jlog_file *f, void **base, size_t *len)
245 {
246   struct stat sb;
247   void *my_map;
248   int flags = 0;
249
250 #ifdef MAP_SHARED
251   flags = MAP_SHARED;
252 #endif
253   if (fstat(f->fd, &sb) != 0) return 0;
254   my_map = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, flags, f->fd, 0);
255   if (my_map == MAP_FAILED) return 0;
256   *base = my_map;
257   *len = sb.st_size;
258   return 1;
259 }
260
261 int jlog_file_map_read(jlog_file *f, void **base, size_t *len)
262 {
263   struct stat sb;
264   void *my_map;
265   int flags = 0;
266
267 #ifdef MAP_SHARED
268   flags = MAP_SHARED;
269 #endif
270   if (fstat(f->fd, &sb) != 0) return 0;
271   my_map = mmap(NULL, sb.st_size, PROT_READ, flags, f->fd, 0);
272   if (my_map == MAP_FAILED) return 0;
273   *base = my_map;
274   *len = sb.st_size;
275   return 1;
276 }
277
278 off_t jlog_file_size(jlog_file *f)
279 {
280   struct stat sb;
281   int rv;
282   while ((rv = fstat(f->fd, &sb)) == -1 && errno == EINTR) ;
283   if (rv != 0) return -1;
284   return sb.st_size;
285 }
286
287 int jlog_file_truncate(jlog_file *f, off_t len)
288 {
289   int rv;
290   while ((rv = ftruncate(f->fd, len)) == -1 && errno == EINTR) ;
291   if (rv == 0) return 1;
292   return 0;
293 }
294
295 /* vim:se ts=2 sw=2 et: */
Note: See TracBrowser for help on using the browser.