Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
io.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /* Copyright(C) 2009-2012 Brazil
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License version 2.1 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Lesser General Public License for more details.
12 
13  You should have received a copy of the GNU Lesser General Public
14  License along with this library; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include "groonga_in.h"
19 
20 #include <stdio.h>
21 
22 #ifndef __USE_GNU
23 #define __USE_GNU /* O_DIRECT */
24 #endif /* __USE_GNU */
25 #include <fcntl.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 
29 #include "ctx.h"
30 #include "io.h"
31 #include "plugin_in.h"
32 #include "hash.h"
33 #include "ctx_impl.h"
34 
35 #define GRN_IO_IDSTR "GROONGA:IO:00001"
36 
37 /* VA hack */
38 /* max aio request (/proc/sys/fs/aio-max-nr) */
39 #define MAX_REQUEST (64*1024)
40 
41 #define MEM_ALIGN grn_cache_block
42 
43 /* end VA hack */
44 
45 #ifndef O_BINARY
46 # ifdef _O_BINARY
47 # define O_BINARY _O_BINARY
48 # else
49 # define O_BINARY 0
50 # endif
51 #endif
52 
53 typedef struct _grn_io_fileinfo {
54 #ifdef WIN32
55  HANDLE fh;
56  HANDLE fmo;
57  grn_critical_section cs;
58 #else /* WIN32 */
59  int fd;
60  dev_t dev;
61  ino_t inode;
62 #endif /* WIN32 */
63 } fileinfo;
64 
65 #define IO_HEADER_SIZE 64
66 
67 inline static grn_rc grn_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags, size_t maxsize);
68 inline static void grn_fileinfo_init(fileinfo *fis, int nfis);
69 inline static int grn_opened(fileinfo *fi);
70 inline static grn_rc grn_close(grn_ctx *ctx, fileinfo *fi);
71 #if defined(WIN32) && defined(WIN32_FMO_EACH)
72 inline static void * grn_mmap(grn_ctx *ctx, HANDLE *fmo, fileinfo *fi,
73  off_t offset, size_t length);
74 inline static int grn_munmap(grn_ctx *ctx, HANDLE *fmo, void *start, size_t length);
75 #define GRN_MMAP(ctx,fmo,fi,offset,length)\
76  (grn_mmap((ctx), (fmo), (fi), (offset), (length)))
77 #define GRN_MUNMAP(ctx,fmo,start,length) (grn_munmap((ctx), (fmo), (start), (length)))
78 #else /* defined(WIN32) && defined(WIN32_FMO_EACH) */
79 inline static void * grn_mmap(grn_ctx *ctx, fileinfo *fi, off_t offset, size_t length);
80 inline static int grn_munmap(grn_ctx *ctx, void *start, size_t length);
81 #define GRN_MUNMAP(ctx,fmo,start,length) (grn_munmap((ctx), (start), (length)))
82 #ifdef USE_FAIL_MALLOC
83 inline static void * grn_fail_mmap(grn_ctx *ctx, fileinfo *fi,
84  off_t offset, size_t length,
85  const char* file, int line, const char *func);
86 #define GRN_MMAP(ctx,fmo,fi,offset,length) \
87  (grn_fail_mmap((ctx), (fi), (offset), (length), __FILE__, __LINE__, __FUNCTION__))
88 #else /* USE_FAIL_MALLOC */
89 #define GRN_MMAP(ctx,fmo,fi,offset,length) (grn_mmap((ctx), (fi), (offset), (length)))
90 #endif /* USE_FAIL_MALLOC */
91 #endif /* defined(WIN32) && defined(WIN32_FMO_EACH) */
92 inline static int grn_msync(grn_ctx *ctx, void *start, size_t length);
93 inline static grn_rc grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset);
94 inline static grn_rc grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset);
95 
96 grn_rc
98 {
99  return GRN_SUCCESS;
100 }
101 
102 grn_rc
104 {
105  return GRN_SUCCESS;
106 }
107 
108 grn_io *
109 grn_io_create_tmp(uint32_t header_size, uint32_t segment_size,
110  uint32_t max_segment, grn_io_mode mode, uint32_t flags)
111 {
112  grn_io *io;
113  unsigned int b;
114  uint32_t total_header_size;
115  struct _grn_io_header *header;
116  total_header_size = IO_HEADER_SIZE + header_size;
117  b = (total_header_size + grn_pagesize - 1) & ~(grn_pagesize - 1);
118  if ((header = (struct _grn_io_header *)GRN_MMAP(&grn_gctx, NULL, NULL, 0, b))) {
119  header->header_size = header_size;
120  header->segment_size = segment_size;
121  header->max_segment = max_segment;
122  header->n_arrays = 0;
123  header->flags = flags;
124  header->lock = 0;
125  memcpy(header->idstr, GRN_IO_IDSTR, 16);
126  if ((io = GRN_GMALLOCN(grn_io, 1))) {
127  grn_io_mapinfo *maps = NULL;
128  if (((maps = GRN_GMALLOCN(grn_io_mapinfo, max_segment)) &&
129  memset(maps, 0, sizeof(grn_io_mapinfo) * max_segment))) {
130  io->header = header;
131  io->user_header = (((byte *) header) + IO_HEADER_SIZE);
132  io->maps = maps;
133  io->base = b;
134  io->base_seg = 0;
135  io->mode = mode;
136  io->header->curr_size = b;
137  io->fis = NULL;
138  io->ainfo = NULL;
139  io->max_map_seg = 0;
140  io->nmaps = 0;
141  io->count = 0;
142  io->flags = GRN_IO_TEMPORARY;
143  io->lock = &header->lock;
144  io->path[0] = '\0';
145  return io;
146  }
147  GRN_GFREE(io);
148  }
149  GRN_MUNMAP(&grn_gctx, NULL, header, b);
150  }
151  return NULL;
152 }
153 
154 static void
155 grn_io_register(grn_io *io)
156 {
157  if (io->fis && (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
158  grn_bool succeeded = GRN_FALSE;
159  CRITICAL_SECTION_ENTER(grn_glock);
160  if (grn_gctx.impl && grn_gctx.impl->ios &&
161  grn_hash_add(&grn_gctx, grn_gctx.impl->ios, io->path, strlen(io->path),
162  (void **)&io, NULL)) {
163  succeeded = GRN_TRUE;
164  }
165  CRITICAL_SECTION_LEAVE(grn_glock);
166  if (!succeeded) {
168  "grn_io_register(%s) failed", io->path);
169  }
170  }
171 }
172 
173 static void
174 grn_io_unregister(grn_io *io)
175 {
176  if (io->fis && (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
177  grn_bool succeeded = GRN_FALSE;
178  CRITICAL_SECTION_ENTER(grn_glock);
179  if (grn_gctx.impl && grn_gctx.impl->ios) {
181  io->path, strlen(io->path), NULL);
182  succeeded = GRN_TRUE;
183  }
184  CRITICAL_SECTION_LEAVE(grn_glock);
185  if (!succeeded) {
187  "grn_io_unregister(%s) failed", io->path);
188  }
189  }
190 }
191 
192 grn_io *
193 grn_io_create(grn_ctx *ctx, const char *path, uint32_t header_size, uint32_t segment_size,
194  uint32_t max_segment, grn_io_mode mode, uint32_t flags)
195 {
196  grn_io *io;
197  fileinfo *fis;
198  unsigned int b, max_nfiles;
199  uint32_t bs, total_header_size;
200  struct _grn_io_header *header;
201  if (!path) {
202  return grn_io_create_tmp(header_size, segment_size, max_segment, mode, flags);
203  }
204  if (!*path || (strlen(path) > PATH_MAX - 4)) { return NULL; }
205  total_header_size = IO_HEADER_SIZE + header_size;
206  b = (total_header_size + grn_pagesize - 1) & ~(grn_pagesize - 1);
207  bs = (b + segment_size - 1) / segment_size;
208  max_nfiles = (unsigned int)(
209  ((uint64_t)segment_size * (max_segment + bs) + GRN_IO_FILE_SIZE - 1)
210  / GRN_IO_FILE_SIZE);
211  if ((fis = GRN_GMALLOCN(fileinfo, max_nfiles))) {
212  grn_fileinfo_init(fis, max_nfiles);
213  if (!grn_open(ctx, fis, path, O_RDWR|O_CREAT|O_EXCL, GRN_IO_FILE_SIZE)) {
214  if ((header = (struct _grn_io_header *)GRN_MMAP(&grn_gctx, &fis->fmo, fis, 0, b))) {
215  header->header_size = header_size;
216  header->segment_size = segment_size;
217  header->max_segment = max_segment;
218  header->n_arrays = 0;
219  header->flags = flags;
220  header->lock = 0;
221  memcpy(header->idstr, GRN_IO_IDSTR, 16);
222  grn_msync(ctx, header, b);
223  if ((io = GRN_GMALLOCN(grn_io, 1))) {
224  grn_io_mapinfo *maps = NULL;
225  if (((maps = GRN_GMALLOCN(grn_io_mapinfo, max_segment)) &&
226  memset(maps, 0, sizeof(grn_io_mapinfo) * max_segment))) {
227  strncpy(io->path, path, PATH_MAX);
228  io->header = header;
229  io->user_header = (((byte *) header) + IO_HEADER_SIZE);
230  io->maps = maps;
231  io->base = b;
232  io->base_seg = bs;
233  io->mode = mode;
234  io->header->curr_size = b;
235  io->fis = fis;
236  io->ainfo = NULL;
237  io->max_map_seg = 0;
238  io->nmaps = 0;
239  io->count = 0;
240  io->flags = flags;
241  io->lock = &header->lock;
242  grn_io_register(io);
243  return io;
244  }
245  GRN_GFREE(io);
246  }
247  GRN_MUNMAP(&grn_gctx, &fis->fmo, header, b);
248  }
249  grn_close(ctx, fis);
250  }
251  GRN_GFREE(fis);
252  }
253  return NULL;
254 }
255 
256 static grn_rc
257 array_init_(grn_io *io, int n_arrays, size_t hsize, size_t msize)
258 {
259  int i;
260  uint32_t ws;
261  byte *hp, *mp;
262  grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
263  hp = io->user_header;
264  if (!(mp = GRN_GCALLOC(msize))) {
266  }
267  io->ainfo = (grn_io_array_info *)mp;
268  hp += sizeof(grn_io_array_spec) * n_arrays;
269  mp += sizeof(grn_io_array_info) * n_arrays;
270  for (ws = 0; (1 << ws) < io->header->segment_size; ws++);
271  for (i = 0; i < n_arrays; i++) {
272  uint32_t we = ws - array_specs[i].w_of_element;
273  io->ainfo[i].w_of_elm_in_a_segment = we;
274  io->ainfo[i].elm_mask_in_a_segment = (1 << we) - 1;
275  io->ainfo[i].max_n_segments = array_specs[i].max_n_segments;
276  io->ainfo[i].element_size = 1 << array_specs[i].w_of_element;
277  io->ainfo[i].segments = (uint32_t *)hp;
278  io->ainfo[i].addrs = (void **)mp;
279  hp += sizeof(uint32_t) * array_specs[i].max_n_segments;
280  mp += sizeof(void *) * array_specs[i].max_n_segments;
281  }
282  io->user_header += hsize;
283  return GRN_SUCCESS;
284 }
285 
286 static grn_rc
287 array_init(grn_io *io, int n_arrays)
288 {
289  if (n_arrays) {
290  int i;
291  grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
292  size_t hsize = sizeof(grn_io_array_spec) * n_arrays;
293  size_t msize = sizeof(grn_io_array_info) * n_arrays;
294  for (i = 0; i < n_arrays; i++) {
295  hsize += sizeof(uint32_t) * array_specs[i].max_n_segments;
296  msize += sizeof(void *) * array_specs[i].max_n_segments;
297  }
298  return array_init_(io, n_arrays, hsize, msize);
299  }
300  return GRN_SUCCESS;
301 }
302 
303 grn_io *
304 grn_io_create_with_array(grn_ctx *ctx, const char *path,
305  uint32_t header_size, uint32_t segment_size,
306  grn_io_mode mode, int n_arrays, grn_io_array_spec *array_specs)
307 {
308  if (n_arrays) {
309  int i;
310  grn_io *io;
311  byte *hp;
312  uint32_t nsegs = 0;
313  size_t hsize = sizeof(grn_io_array_spec) * n_arrays;
314  size_t msize = sizeof(grn_io_array_info) * n_arrays;
315  for (i = 0; i < n_arrays; i++) {
316  nsegs += array_specs[i].max_n_segments;
317  hsize += sizeof(uint32_t) * array_specs[i].max_n_segments;
318  msize += sizeof(void *) * array_specs[i].max_n_segments;
319  }
320  if ((io = grn_io_create(ctx, path, header_size + hsize,
321  segment_size, nsegs, mode, GRN_IO_EXPIRE_GTICK))) {
322  hp = io->user_header;
323  memcpy(hp, array_specs, sizeof(grn_io_array_spec) * n_arrays);
324  io->header->n_arrays = n_arrays;
325  io->header->segment_tail = 1;
326  if (!array_init_(io, n_arrays, hsize, msize)) {
327  return io;
328  }
329  ERR(GRN_NO_MEMORY_AVAILABLE, "grn_io_create_with_array failed");
330  grn_io_close(ctx, io);
331  }
332  }
333  return NULL;
334 }
335 
336 inline static uint32_t
337 segment_alloc(grn_io *io)
338 {
339  uint32_t n, s;
340  grn_io_array_info *ai;
341  if (io->header->segment_tail) {
342  if (io->header->segment_tail > io->header->max_segment) {
343  s = 0;
344  } else {
345  s = io->header->segment_tail++;
346  }
347  } else {
348  char *used = GRN_GCALLOC(io->header->max_segment + 1);
349  if (!used) { return 0; }
350  for (n = io->header->n_arrays, ai = io->ainfo; n; n--, ai++) {
351  for (s = 0; s < ai->max_n_segments; s++) {
352  used[ai->segments[s]] = 1;
353  }
354  }
355  for (s = 1; ; s++) {
356  if (s > io->header->max_segment) {
357  io->header->segment_tail = s;
358  s = 0;
359  break;
360  }
361  if (!used[s]) {
362  io->header->segment_tail = s + 1;
363  break;
364  }
365  }
366  GRN_GFREE(used);
367  }
368  return s;
369 }
370 
371 void
372 grn_io_segment_alloc(grn_ctx *ctx, grn_io *io, grn_io_array_info *ai, uint32_t lseg, int *flags, void **p)
373 {
374  uint32_t *sp = &ai->segments[lseg];
375  if (!*sp) {
376  if ((*flags & GRN_TABLE_ADD)) {
377  if ((*sp = segment_alloc(io))) {
378  *flags |= GRN_TABLE_ADDED;
379  }
380  }
381  }
382  if (*sp) {
383  uint32_t pseg = *sp - 1;
384  GRN_IO_SEG_REF(io, pseg, *p);
385  if (*p) { GRN_IO_SEG_UNREF(io, pseg); };
386  }
387 }
388 
389 void *
390 grn_io_array_at(grn_ctx *ctx, grn_io *io, uint32_t array, off_t offset, int *flags)
391 {
392  void *res;
393  GRN_IO_ARRAY_AT(io,array,offset,flags,res);
394  return res;
395 }
396 
397 uint32_t
398 grn_io_detect_type(grn_ctx *ctx, const char *path)
399 {
400  struct _grn_io_header h;
401  uint32_t res = 0;
402  int fd = GRN_OPEN(path, O_RDWR | O_BINARY);
403  if (fd != -1) {
404  struct stat s;
405  if (fstat(fd, &s) != -1 && s.st_size >= sizeof(struct _grn_io_header)) {
406  if (read(fd, &h, sizeof(struct _grn_io_header)) == sizeof(struct _grn_io_header)) {
407  if (!memcmp(h.idstr, GRN_IO_IDSTR, 16)) {
408  res = h.type;
409  } else {
410  ERR(GRN_INCOMPATIBLE_FILE_FORMAT, "incompatible file format");
411  }
412  } else {
413  SERR(path);
414  }
415  } else {
416  ERR(GRN_INVALID_FORMAT, "grn_io_detect_type failed");
417  }
418  GRN_CLOSE(fd);
419  } else {
420  SERR(path);
421  }
422  return res;
423 }
424 
425 grn_io *
426 grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode)
427 {
428  grn_io *io;
429  struct stat s;
430  fileinfo *fis;
431  uint32_t flags = 0;
432  unsigned int b, max_nfiles;
433  uint32_t total_header_size;
434  uint32_t header_size = 0, segment_size = 0, max_segment = 0, bs;
435  if (!path || !*path || (strlen(path) > PATH_MAX - 4)) { return NULL; }
436  {
437  struct _grn_io_header h;
438  int fd = GRN_OPEN(path, O_RDWR | O_BINARY);
439  if (fd == -1) { SERR(path); return NULL; }
440  if (fstat(fd, &s) != -1 && s.st_size >= sizeof(struct _grn_io_header)) {
441  if (read(fd, &h, sizeof(struct _grn_io_header)) == sizeof(struct _grn_io_header)) {
442  if (!memcmp(h.idstr, GRN_IO_IDSTR, 16)) {
443  header_size = h.header_size;
446  flags = h.flags;
447  } else {
448  ERR(GRN_INCOMPATIBLE_FILE_FORMAT, "incompatible file format");
449  }
450  }
451  }
452  GRN_CLOSE(fd);
453  if (!segment_size) { return NULL; }
454  }
455  total_header_size = IO_HEADER_SIZE + header_size;
456  b = (total_header_size + grn_pagesize - 1) & ~(grn_pagesize - 1);
457  bs = (b + segment_size - 1) / segment_size;
458  max_nfiles = (unsigned int)(
459  ((uint64_t)segment_size * (max_segment + bs) + GRN_IO_FILE_SIZE - 1)
460  / GRN_IO_FILE_SIZE);
461  if (!(fis = GRN_GMALLOCN(fileinfo, max_nfiles))) { return NULL; }
462  grn_fileinfo_init(fis, max_nfiles);
463  if (!grn_open(ctx, fis, path, O_RDWR, GRN_IO_FILE_SIZE)) {
464  struct _grn_io_header *header;
465  if ((header = GRN_MMAP(&grn_gctx, &fis->fmo, fis, 0, b))) {
466  if ((io = GRN_GMALLOC(sizeof(grn_io)))) {
467  grn_io_mapinfo *maps = NULL;
468  if ((maps = GRN_GCALLOC(sizeof(grn_io_mapinfo) * max_segment))) {
469  strncpy(io->path, path, PATH_MAX);
470  io->header = header;
471  io->user_header = (((byte *) header) + IO_HEADER_SIZE);
472  {
473  io->maps = maps;
474  io->base = b;
475  io->base_seg = bs;
476  io->mode = mode;
477  io->fis = fis;
478  io->ainfo = NULL;
479  io->max_map_seg = 0;
480  io->nmaps = 0;
481  io->count = 0;
482  io->flags = header->flags;
483  io->lock = &header->lock;
484  if (!array_init(io, io->header->n_arrays)) {
485  grn_io_register(io);
486  return io;
487  }
488  }
489  if (io->maps) { GRN_GFREE(io->maps); }
490  }
491  GRN_GFREE(io);
492  }
493  GRN_MUNMAP(&grn_gctx, &fis->fmo, header, b);
494  }
495  grn_close(ctx, fis);
496  }
497  GRN_GFREE(fis);
498  return NULL;
499 }
500 
501 grn_rc
503 {
504  int i;
505  grn_io_mapinfo *mi;
506  fileinfo *fi;
507  uint32_t bs = io->base_seg;
508  uint32_t max_segment = io->header->segment_tail
509  ? io->header->segment_tail : io->header->max_segment;
510  uint32_t segment_size = io->header->segment_size;
511  unsigned int max_nfiles = (unsigned int)(
512  ((uint64_t)segment_size * (max_segment + bs) + GRN_IO_FILE_SIZE - 1)
513  / GRN_IO_FILE_SIZE);
514  grn_io_unregister(io);
515  if (io->ainfo) { GRN_GFREE(io->ainfo); }
516  if (io->maps) {
517  for (mi = io->maps, i = max_segment; i; mi++, i--) {
518  if (mi->map) {
519  /* if (atomic_read(mi->nref)) { return STILL_IN_USE ; } */
520 #ifdef WIN32
521  if ((io->flags & GRN_IO_TEMPORARY)) {
522  GRN_GFREE(mi->map);
523  } else
524 #endif /* WIN32 */
525  GRN_MUNMAP(&grn_gctx, &mi->fmo, mi->map, segment_size);
526  }
527  }
528  GRN_GFREE(io->maps);
529  }
530 #ifdef WIN32
531  if ((io->flags & GRN_IO_TEMPORARY)) {
532  GRN_GFREE(io->header);
533  } else
534 #endif /* WIN32 */
535  GRN_MUNMAP(&grn_gctx, &io->fis->fmo, io->header, io->base);
536  if (io->fis) {
537  for (fi = io->fis, i = max_nfiles; i; fi++, i--) { grn_close(ctx, fi); }
538  GRN_GFREE(io->fis);
539  }
540  GRN_GFREE(io);
541  return GRN_SUCCESS;
542 }
543 
544 uint32_t
546 {
547  return io->base_seg;
548 }
549 
550 const char *
552 {
553  return io->path;
554 }
555 
556 void *
558 {
559  return io->user_header;
560 }
561 
562 grn_rc
564 {
565  if (!io || !io->header) {
566  return GRN_INVALID_ARGUMENT;
567  }
568  io->header->type = type;
569  return GRN_SUCCESS;
570 }
571 
572 uint32_t
574 {
575  if (!io || !io->header) { return GRN_VOID; }
576  return io->header->type;
577 }
578 
579 inline static void
580 gen_pathname(const char *path, char *buffer, int fno)
581 {
582  size_t len = strlen(path);
583  memcpy(buffer, path, len);
584  if (fno) {
585  buffer[len] = '.';
586  grn_itoh(fno, buffer + len + 1, 3);
587  buffer[len + 4] = '\0';
588  } else {
589  buffer[len] = '\0';
590  }
591 }
592 
593 grn_rc
594 grn_io_size(grn_ctx *ctx, grn_io *io, uint64_t *size)
595 {
596  int fno;
597  struct stat s;
598  uint64_t tsize = 0;
599  char buffer[PATH_MAX];
600  uint32_t nfiles;
601  if (io->header->curr_size) {
602  nfiles = (uint32_t) ((io->header->curr_size + GRN_IO_FILE_SIZE - 1) / GRN_IO_FILE_SIZE);
603  } else {
604  uint32_t bs = io->base_seg;
605  uint32_t max_segment = io->header->max_segment;
606  uint32_t segment_size = io->header->segment_size;
607  nfiles = (uint32_t) (((uint64_t)segment_size * (max_segment + bs) + GRN_IO_FILE_SIZE - 1)
608  / GRN_IO_FILE_SIZE);
609  }
610  for (fno = 0; fno < nfiles; fno++) {
611  gen_pathname(io->path, buffer, fno);
612  if (stat(buffer, &s)) {
613  SERR(buffer);
614  } else {
615  tsize += s.st_size;
616  }
617  }
618  *size = tsize;
619  return GRN_SUCCESS;
620 }
621 
622 grn_rc
623 grn_io_remove(grn_ctx *ctx, const char *path)
624 {
625  struct stat s;
626  if (stat(path, &s)) {
627  SERR("stat");
628  return ctx->rc;
629  } else if (unlink(path)) {
630  SERR(path);
631  return ctx->rc;
632  } else {
633  int fno;
634  char buffer[PATH_MAX];
635  for (fno = 1; ; fno++) {
636  gen_pathname(path, buffer, fno);
637  if (!stat(buffer, &s)) {
638  if (unlink(buffer)) { SERR(buffer); }
639  } else {
640  break;
641  }
642  }
643  return GRN_SUCCESS;
644  }
645 }
646 
647 grn_rc
648 grn_io_rename(grn_ctx *ctx, const char *old_name, const char *new_name)
649 {
650  struct stat s;
651  if (stat(old_name, &s)) {
652  SERR("stat");
653  return ctx->rc;
654  } else if (rename(old_name, new_name)) {
655  SERR(old_name);
656  return ctx->rc;
657  } else {
658  int fno;
659  char old_buffer[PATH_MAX];
660  char new_buffer[PATH_MAX];
661  for (fno = 1; ; fno++) {
662  gen_pathname(old_name, old_buffer, fno);
663  if (!stat(old_buffer, &s)) {
664  gen_pathname(new_name, new_buffer, fno);
665  if (rename(old_buffer, new_buffer)) { SERR(old_buffer); }
666  } else {
667  SERR("stat");
668  return ctx->rc;
669  }
670  }
671  return GRN_SUCCESS;
672  }
673 }
674 
675 typedef struct {
677  char body[256];
678 } ja_element;
679 
680 grn_rc
681 grn_io_read_ja(grn_io *io, grn_ctx *ctx, grn_io_ja_einfo *einfo, uint32_t epos, uint32_t key,
682  uint32_t segment, uint32_t offset, void **value, uint32_t *value_len)
683 {
684  uint32_t rest = 0, size = *value_len + sizeof(grn_io_ja_ehead);
685  uint32_t segment_size = io->header->segment_size;
686  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
687  uint32_t bseg = segment + io->base_seg;
688  int fno = bseg / segments_per_file;
689  fileinfo *fi = &io->fis[fno];
690  off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
691  off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
692  ja_element *v = GRN_MALLOC(size);
693  if (!v) {
694  *value = NULL;
695  *value_len = 0;
697  }
698  if (pos + size > GRN_IO_FILE_SIZE) {
699  rest = pos + size - GRN_IO_FILE_SIZE;
700  size = GRN_IO_FILE_SIZE - pos;
701  }
702  if (!grn_opened(fi)) {
703  char path[PATH_MAX];
704  gen_pathname(io->path, path, fno);
705  if (grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE)) {
706  *value = NULL;
707  *value_len = 0;
708  GRN_FREE(v);
709  return ctx->rc;
710  }
711  }
712  if (grn_pread(ctx, fi, v, size, pos)) {
713  *value = NULL;
714  *value_len = 0;
715  GRN_FREE(v);
716  return ctx->rc;
717  }
718  if (einfo->pos != epos) {
719  GRN_LOG(ctx, GRN_LOG_WARNING, "einfo pos changed %x => %x", einfo->pos, epos);
720  *value = NULL;
721  *value_len = 0;
722  GRN_FREE(v);
723  return GRN_FILE_CORRUPT;
724  }
725  if (einfo->size != *value_len) {
726  GRN_LOG(ctx, GRN_LOG_WARNING, "einfo size changed %d => %d", einfo->size, *value_len);
727  *value = NULL;
728  *value_len = 0;
729  GRN_FREE(v);
730  return GRN_FILE_CORRUPT;
731  }
732  if (v->head.key != key) {
733  GRN_LOG(ctx, GRN_LOG_ERROR, "ehead key unmatch %x => %x", key, v->head.key);
734  *value = NULL;
735  *value_len = 0;
736  GRN_FREE(v);
737  return GRN_INVALID_FORMAT;
738  }
739  if (v->head.size != *value_len) {
740  GRN_LOG(ctx, GRN_LOG_ERROR, "ehead size unmatch %d => %d", *value_len, v->head.size);
741  *value = NULL;
742  *value_len = 0;
743  GRN_FREE(v);
744  return GRN_INVALID_FORMAT;
745  }
746  if (rest) {
747  byte *vr = (byte *)v + size;
748  do {
749  fi = &io->fis[++fno];
750  if (!grn_opened(fi)) {
751  char path[PATH_MAX];
752  gen_pathname(io->path, path, fno);
753  if (grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE)) {
754  *value = NULL;
755  *value_len = 0;
756  GRN_FREE(v);
757  return ctx->rc;
758  }
759  }
760  size = rest > GRN_IO_FILE_SIZE ? GRN_IO_FILE_SIZE : rest;
761  if (grn_pread(ctx, fi, vr, size, 0)) {
762  *value = NULL;
763  *value_len = 0;
764  GRN_FREE(v);
765  return ctx->rc;
766  }
767  vr += size;
768  rest -= size;
769  } while (rest);
770  }
771  *value = v->body;
772  return GRN_SUCCESS;
773 }
774 
775 grn_rc
776 grn_io_write_ja(grn_io *io, grn_ctx *ctx, uint32_t key,
777  uint32_t segment, uint32_t offset, void *value, uint32_t value_len)
778 {
779  grn_rc rc;
780  uint32_t rest = 0, size = value_len + sizeof(grn_io_ja_ehead);
781  uint32_t segment_size = io->header->segment_size;
782  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
783  uint32_t bseg = segment + io->base_seg;
784  int fno = bseg / segments_per_file;
785  fileinfo *fi = &io->fis[fno];
786  off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
787  off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
788  if (pos + size > GRN_IO_FILE_SIZE) {
789  rest = pos + size - GRN_IO_FILE_SIZE;
790  size = GRN_IO_FILE_SIZE - pos;
791  }
792  if (!grn_opened(fi)) {
793  char path[PATH_MAX];
794  gen_pathname(io->path, path, fno);
795  if ((rc = grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE))) { return rc; }
796  }
797  if (value_len <= 256) {
798  ja_element je;
799  je.head.size = value_len;
800  je.head.key = key;
801  memcpy(je.body, value, value_len);
802  rc = grn_pwrite(ctx, fi, &je, size, pos);
803  } else {
804  grn_io_ja_ehead eh;
805  eh.size = value_len;
806  eh.key = key;
807  if ((rc = grn_pwrite(ctx, fi, &eh, sizeof(grn_io_ja_ehead), pos))) { return rc; }
808  pos += sizeof(grn_io_ja_ehead);
809  rc = grn_pwrite(ctx, fi, value, size - sizeof(grn_io_ja_ehead), pos);
810  }
811  if (rc) { return rc; }
812  if (rest) {
813  byte *vr = (byte *)value + size - sizeof(grn_io_ja_ehead);
814  do {
815  fi = &io->fis[++fno];
816  if (!grn_opened(fi)) {
817  char path[PATH_MAX];
818  gen_pathname(io->path, path, fno);
819  if ((rc = grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE))) { return rc; }
820  }
821  size = rest > GRN_IO_FILE_SIZE ? GRN_IO_FILE_SIZE : rest;
822  if ((rc = grn_pwrite(ctx, fi, vr, size, 0))) { return rc; }
823  vr += size;
824  rest -= size;
825  } while (rest);
826  }
827  return rc;
828 }
829 
830 grn_rc
831 grn_io_write_ja_ehead(grn_io *io, grn_ctx *ctx, uint32_t key,
832  uint32_t segment, uint32_t offset, uint32_t value_len)
833 {
834  grn_rc rc;
835  uint32_t segment_size = io->header->segment_size;
836  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
837  uint32_t bseg = segment + io->base_seg;
838  int fno = bseg / segments_per_file;
839  fileinfo *fi = &io->fis[fno];
840  off_t base = fno ? 0 : io->base - (uint64_t)segment_size + io->base_seg;
841  off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
842  if (!grn_opened(fi)) {
843  char path[PATH_MAX];
844  gen_pathname(io->path, path, fno);
845  if ((rc = grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE))) { return rc; }
846  }
847  {
848  grn_io_ja_ehead eh;
849  eh.size = value_len;
850  eh.key = key;
851  return grn_pwrite(ctx, fi, &eh, sizeof(grn_io_ja_ehead), pos);
852  }
853 }
854 
855 void *
856 grn_io_win_map(grn_io *io, grn_ctx *ctx, grn_io_win *iw, uint32_t segment,
857  uint32_t offset, uint32_t size, grn_io_rw_mode mode)
858 {
859  byte *p;
860  off_t pos, base;
861  int fno;
862  uint32_t nseg, bseg;
863  uint32_t segment_size = io->header->segment_size;
864  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
865  iw->ctx = ctx;
866  iw->diff = 0;
867  if (offset >= segment_size) {
868  segment += offset / segment_size;
869  offset = offset % segment_size;
870  }
871  nseg = (offset + size + segment_size - 1) / segment_size;
872  bseg = segment + io->base_seg;
873  fno = bseg / segments_per_file;
874  base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
875  pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
876  if (!size || !io || segment + nseg > io->header->max_segment ||
877  fno != (bseg + nseg - 1) / segments_per_file) {
878  return NULL;
879  }
880  switch (mode) {
881  case grn_io_rdonly:
882  {
883  fileinfo *fi = &io->fis[fno];
884  if (!grn_opened(fi)) {
885  char path[PATH_MAX];
886  gen_pathname(io->path, path, fno);
887  if (grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE)) {
888  return NULL;
889  }
890  }
891  if (!(p = GRN_MALLOC(size))) { return NULL; }
892  if (grn_pread(ctx, fi, p, size, pos)) {
893  GRN_FREE(p);
894  return NULL;
895  }
896  iw->addr = p;
897  }
898  break;
899  case grn_io_rdwr:
900  // if (nseg > 1) { /* auto unmap is not implemented yet */
901  if (nseg > 0) {
902  fileinfo *fi = &io->fis[fno];
903  if (!grn_opened(fi)) {
904  char path[PATH_MAX];
905  gen_pathname(io->path, path, fno);
906  if (grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE)) {
907  return NULL;
908  }
909  }
910  if (!(p = GRN_MMAP(&grn_gctx, &iw->fmo, fi, pos, (uint64_t)segment_size * nseg))) {
911  return NULL;
912  }
913  {
914  uint64_t tail = io->base + (uint64_t)segment_size * segment + offset + size;
915  if (tail > io->header->curr_size) { io->header->curr_size = tail; }
916  }
917  } else {
918  GRN_LOG(ctx, GRN_LOG_ALERT, "nseg == 0! in grn_io_win_map(%p, %u, %u, %u)", io, segment, offset, size);
919  // GRN_IO_SEG_REF(io, segment, p); if (!p) { return NULL; }
920  return NULL;
921  }
922  iw->addr = p + offset;
923  break;
924  case grn_io_wronly:
925  if (!(p = GRN_MALLOC(size))) { return NULL; }
926  memset(p, 0, size);
927  iw->cached = 0;
928  iw->addr = p;
929  break;
930  default :
931  return NULL;
932  }
933  iw->io = io;
934  iw->mode = mode;
935  iw->segment = segment;
936  iw->offset = offset;
937  iw->nseg = nseg;
938  iw->size = size;
939  iw->pos = pos;
940  return iw->addr;
941 }
942 
943 #ifdef USE_AIO
944 grn_rc
945 grn_io_win_mapv(grn_io_win **list, grn_ctx *ctx, int nent)
946 {
947  int i;
948  grn_io_win *iw;
949  struct aiocb *iocbs[MAX_REQUEST];
950  struct aiocb iocb[MAX_REQUEST];
951  CacheIOOper oper[MAX_REQUEST];
952  int count = 0;
953 
954  grn_io_win **clist = list;
955  int cl = 0;
956 
957 retry:
958  for (i = 0; i < nent; i++) {
959  iw = list[i];
960  if (grn_aio_enabled && iw->mode == grn_io_rdonly) {
961  /* this block is same as grn_io_win_map() */
962  grn_io *io = iw->io;
963  uint32_t segment = iw->segment, offset = iw->offset, size = iw->size;
964  byte *p;
965  off_t pos, base;
966  int fno;
967  uint32_t nseg, bseg;
968  uint32_t segment_size = io->header->segment_size;
969  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
970  fileinfo *fi;
971  iw->diff = 0;
972  if (offset >= segment_size) {
973  segment += offset / segment_size;
974  offset = offset % segment_size;
975  }
976  nseg = (offset + size + segment_size - 1) / segment_size;
977  bseg = segment + io->base_seg;
978  fno = bseg / segments_per_file;
979  base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
980  pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
981  if (!size || !io || segment + nseg > io->header->max_segment ||
982  fno != (bseg + nseg - 1) / segments_per_file) {
983  return GRN_FILE_CORRUPT;
984  }
985  fi = &io->fis[fno];
986  if (!grn_opened(fi)) {
987  char path[PATH_MAX];
988  gen_pathname(io->path, path, fno);
989  if (grn_open(ctx, fi, path, O_RDWR|O_CREAT|O_DIRECT, GRN_IO_FILE_SIZE)) {
990  return ctx->rc;
991  }
992  }
993  {
994  /* AIO + DIO + cache hack */
995  /* calc alignment */
996  // todo : calculate curr_size.
997  off_t voffset = pos - (pos % MEM_ALIGN);
998  uint32_t vsize = pos + size;
999 
1000  vsize = ((vsize - 1) / MEM_ALIGN + 1) * MEM_ALIGN;
1001  vsize = vsize - voffset;
1002 
1003  /* diff of aligned offset */
1004  iw->diff = pos - voffset;
1005 
1006  dp ("pos: %lu, allocate: %d, really needed: %d\n", voffset, vsize, size);
1007  memset(&oper[count], 0, sizeof(CacheIOOper));
1008  memset(&iocb[count], 0, sizeof(struct aiocb));
1009  oper[count].iocb = &iocb[count];
1010  iocb[count].aio_fildes = fi->fd;
1011  iocb[count].aio_lio_opcode = LIO_READ;
1012 
1013  if (vsize <= MEM_ALIGN &&
1014  (p = grn_cache_read (&oper[count], fi->dev, fi->inode, voffset, vsize)) != NULL) {
1015  /* use cache process */
1016  iw->cached = oper[count].cd->num;
1017 
1018  /* Cache require aio_read() or
1019  already aio_read() by other process */
1020  if (oper[count].read == 1) {
1021  iocbs[count] = &iocb[count];
1022  count++; /* aio count */
1023  } else if (oper[count].cd->flag == CACHE_READ) {
1024  /* this iw is ignored in this loop.
1025  should re-check after AIO */
1026  clist[cl++] = iw;
1027  }
1028  } else {
1029  /* This size cannot use Cache */
1030  dp ("Wont use cache offset=%lu size=%u\n", voffset, vsize);
1031 
1032  /* allocate aligned memory */
1033  if (posix_memalign(&p, MEM_ALIGN, vsize) != 0) {
1034  SERR("posix_memalign");
1035  return ctx->rc;
1036  }
1037  iocb[count].aio_buf = p;
1038  iocb[count].aio_nbytes = vsize;
1039  iocb[count].aio_offset = voffset;
1040  iocbs[count] = &iocb[count];
1041 
1042  /* This is not cached */
1043  oper[count].cd = NULL;
1044  iw->cached = -1;
1045 
1046  /* aio count up */
1047  count++;
1048  }
1049  iw->addr = p;
1050  iw->segment = segment;
1051  iw->offset = offset;
1052  iw->nseg = nseg;
1053  iw->size = size;
1054  iw->pos = pos;
1055  } /* End AIO + DIO + cache hack */
1056  } else {
1057  if (!grn_io_win_map(iw->io, ctx, iw, iw->segment, iw->offset, iw->size, iw->mode)) {
1058  return ctx->rc;
1059  }
1060  }
1061  }
1062 
1063  if (grn_aio_enabled) {
1064  if (count > 0) {
1065  int c;
1066 
1067  /* aio_read () */
1068  if (lio_listio (LIO_WAIT, iocbs, count, NULL) < 0) {
1069  SERR("lio_listio");
1070  return ctx->rc;
1071  }
1072  for (c=0;c<count;c++) {
1073  /* cache data is now VALID */
1074  if (oper[c].cd) oper[c].cd->flag = CACHE_VALID;
1075  }
1076  }
1077  if (cl > 0) {
1078  /*
1079  * if previous loop have CACHE_READ CacheData,
1080  * it should retry.
1081  */
1082  dp ("-- Validate Reading state CacheData (%d) --\n", cl);
1083  /* update list and nent for loop */
1084  list = clist; /* list of iw which use CACHE_READ CacheData */
1085  nent = cl; /* number of iw */
1086  cl = 0;
1087  count = 0;
1088  grn_nanosleep(1000);
1089  goto retry;
1090  } else
1091  dp("-- No Reading state CacheData. --\n");
1092  }
1093  return GRN_SUCCESS;
1094 }
1095 #endif /* USE_AIO */
1096 
1097 grn_rc
1099 {
1100  grn_rc rc = GRN_SUCCESS;
1101  grn_io *io = iw->io;
1102  grn_ctx *ctx = iw->ctx;
1103  uint32_t segment_size = io->header->segment_size;
1104  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;
1105  int nseg = iw->nseg;
1106  switch (iw->mode) {
1107  case grn_io_rdonly:
1108 #ifdef USE_AIO
1109  /* VA hack */
1110  if (!grn_aio_enabled || (iw->cached < 0 && iw->addr)) { GRN_FREE(iw->addr); }
1111  else if (iw->cached >= 0){
1112  /* this data is cached */
1113  grn_cache_data_unref (iw->cached);
1114  iw->cached = -1;
1115  }
1116  /* end VA hack */
1117 #else /* USE_AIO */
1118  if (iw->addr) { GRN_FREE(iw->addr); }
1119 #endif /* USE_AIO */
1120  iw->addr = NULL;
1121  break;
1122  case grn_io_rdwr:
1123  // if (nseg > 1) { /* auto unmap is not implemented yet */
1124  if (nseg > 0) {
1125  GRN_MUNMAP(&grn_gctx, &iw->fmo, ((byte *)iw->addr) - iw->offset, (uint64_t)segment_size * nseg);
1126  } else {
1127  if (iw->segment >= io->header->max_segment) {
1128  rc = GRN_INVALID_ARGUMENT;
1129  } else {
1130  //GRN_IO_SEG_UNREF(io, iw->segment);
1131  }
1132 #ifdef USE_AIO
1133  if (grn_aio_enabled) {
1134  int fno = (iw->segment + io->base_seg) / segments_per_file;
1135  fileinfo *fi = &io->fis[fno];
1136  grn_cache_mark_invalid(fi->dev, fi->inode, iw->pos, iw->size);
1137  }
1138 #endif /* USE_AIO */
1139  }
1140  iw->addr = NULL;
1141  break;
1142  case grn_io_wronly:
1143  {
1144  int fno = (iw->segment + io->base_seg) / segments_per_file;
1145  fileinfo *fi = &io->fis[fno];
1146  if (!grn_opened(fi)) {
1147  char path[PATH_MAX];
1148  gen_pathname(io->path, path, fno);
1149  rc = grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE);
1150  }
1151  if (!rc) {
1152  if (!(rc = grn_pwrite(ctx, fi, iw->addr, iw->size, iw->pos))) {
1153  {
1154  uint64_t tail = io->base + (uint64_t)segment_size * iw->segment + iw->offset + iw->size;
1155  if (tail > io->header->curr_size) { io->header->curr_size = tail; }
1156  }
1157  if (!iw->cached) { GRN_FREE(iw->addr); }
1158  iw->addr = NULL;
1159  }
1160 #ifdef USE_AIO
1161  if (grn_aio_enabled) {
1162  grn_cache_mark_invalid(fi->dev, fi->inode, iw->pos, iw->size);
1163  }
1164 #endif /* USE_AIO */
1165  }
1166  }
1167  break;
1168  default :
1169  rc = GRN_INVALID_ARGUMENT;
1170  }
1171  return rc;
1172 }
1173 
1174 void *
1175 grn_io_win_map2(grn_io *io, grn_ctx *ctx, grn_io_win *iw, uint32_t segment,
1176  uint32_t offset, uint32_t size, grn_io_rw_mode mode)
1177 {
1178  uint32_t nseg, segment_size = io->header->segment_size;
1179  if (offset >= segment_size) {
1180  segment += offset / segment_size;
1181  offset = offset % segment_size;
1182  }
1183  nseg = (offset + size + segment_size - 1) / segment_size;
1184  if (!size || !ctx || segment + nseg > io->header->max_segment) { return NULL; }
1185  iw->ctx = ctx;
1186  iw->diff = 0;
1187  iw->io = io;
1188  iw->mode = mode;
1189  iw->tiny_p = 0;
1190  iw->segment = segment;
1191  iw->offset = offset;
1192  iw->nseg = nseg;
1193  iw->size = size;
1194  if (nseg == 1) {
1195  byte *addr = NULL;
1196  GRN_IO_SEG_REF(io, segment, addr);
1197  if (!addr) { return NULL; }
1198  iw->cached = 1;
1199  iw->addr = addr + offset;
1200  } else {
1201  if (!(iw->addr = GRN_MALLOC(size))) { return NULL; }
1202  iw->cached = 0;
1203  switch (mode) {
1204  case grn_io_rdonly:
1205  case grn_io_rdwr:
1206  {
1207  byte *p, *q = NULL;
1208  uint32_t s, r;
1209  for (p = iw->addr, r = size; r; p += s, r -= s, segment++, offset = 0) {
1210  GRN_IO_SEG_REF(io, segment, q);
1211  if (!q) {
1212  GRN_FREE(iw->addr);
1213  return NULL;
1214  }
1215  s = (offset + r > segment_size) ? segment_size - offset : r;
1216  memcpy(p, q + offset, s);
1217  GRN_IO_SEG_UNREF(io, segment);
1218  }
1219  }
1220  break;
1221  case grn_io_wronly:
1222  break;
1223  default :
1224  return NULL;
1225  }
1226  }
1227  return iw->addr;
1228 }
1229 
1230 grn_rc
1232 {
1233  if (!iw || !iw->io ||!iw->ctx) { return GRN_INVALID_ARGUMENT; }
1234  if (iw->cached) {
1235  if (!iw->tiny_p) { GRN_IO_SEG_UNREF(iw->io, iw->segment); }
1236  return GRN_SUCCESS;
1237  }
1238  {
1239  grn_io *io = iw->io;
1240  grn_ctx *ctx = iw->ctx;
1241  switch (iw->mode) {
1242  case grn_io_rdonly:
1243  if (!iw->addr) { return GRN_INVALID_ARGUMENT; }
1244  GRN_FREE(iw->addr);
1245  return GRN_SUCCESS;
1246  case grn_io_rdwr:
1247  case grn_io_wronly:
1248  {
1249  byte *p, *q = NULL;
1250  uint32_t segment_size = io->header->segment_size;
1251  uint32_t s, r, offset = iw->offset, segment = iw->segment;
1252  for (p = iw->addr, r = iw->size; r; p += s, r -= s, segment++, offset = 0) {
1253  GRN_IO_SEG_REF(io, segment, q);
1254  if (!q) { return GRN_NO_MEMORY_AVAILABLE; }
1255  s = (offset + r > segment_size) ? segment_size - offset : r;
1256  memcpy(q + offset, p, s);
1257  GRN_IO_SEG_UNREF(io, segment);
1258  }
1259  }
1260  GRN_FREE(iw->addr);
1261  return GRN_SUCCESS;
1262  default :
1263  return GRN_INVALID_ARGUMENT;
1264  }
1265  }
1266 }
1267 
1268 #define DO_MAP(io,fmo,fi,pos,size,segno,res) do {\
1269  if (((res) = GRN_MMAP(&grn_gctx, (fmo), (fi), (pos), (size)))) {\
1270  uint32_t nmaps;\
1271  if (io->max_map_seg < segno) { io->max_map_seg = segno; }\
1272  GRN_ATOMIC_ADD_EX(&io->nmaps, 1, nmaps);\
1273  {\
1274  uint64_t tail = io->base + (uint64_t)(size) * ((segno) + 1);\
1275  if (tail > io->header->curr_size) { io->header->curr_size = tail; }\
1276  }\
1277  }\
1278 } while (0)
1279 
1280 #define SEG_MAP(io,segno,info) do {\
1281  uint32_t segment_size = io->header->segment_size;\
1282  if ((io->flags & GRN_IO_TEMPORARY)) {\
1283  DO_MAP(io, &info->fmo, NULL, 0, segment_size, segno, info->map);\
1284  } else {\
1285  uint32_t segments_per_file = GRN_IO_FILE_SIZE / segment_size;\
1286  uint32_t bseg = segno + io->base_seg;\
1287  uint32_t fno = bseg / segments_per_file;\
1288  off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;\
1289  off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + base;\
1290  fileinfo *fi = &io->fis[fno];\
1291  if (!grn_opened(fi)) {\
1292  char path[PATH_MAX];\
1293  gen_pathname(io->path, path, fno);\
1294  if (!grn_open(ctx, fi, path, O_RDWR|O_CREAT, GRN_IO_FILE_SIZE)) { \
1295  DO_MAP(io, &info->fmo, fi, pos, segment_size, segno, info->map);\
1296  }\
1297  } else {\
1298  DO_MAP(io, &info->fmo, fi, pos, segment_size, segno, info->map);\
1299  }\
1300  }\
1301 } while (0)
1302 
1303 void
1304 grn_io_seg_map_(grn_ctx *ctx, grn_io *io, uint32_t segno, grn_io_mapinfo *info)
1305 {
1306  SEG_MAP(io, segno, info);
1307 }
1308 
1309 grn_rc
1310 grn_io_seg_expire(grn_ctx *ctx, grn_io *io, uint32_t segno, uint32_t nretry)
1311 {
1312  uint32_t retry, *pnref;
1313  grn_io_mapinfo *info;
1314  if (!io->maps || segno >= io->header->max_segment) { return GRN_INVALID_ARGUMENT; }
1315  info = &io->maps[segno];
1316  if (!info->map) { return GRN_INVALID_ARGUMENT; }
1317  pnref = &info->nref;
1318  for (retry = 0;; retry++) {
1319  uint32_t nref;
1320  GRN_ATOMIC_ADD_EX(pnref, 1, nref);
1321  if (nref) {
1322  GRN_ATOMIC_ADD_EX(pnref, -1, nref);
1323  if (retry >= GRN_IO_MAX_RETRY) {
1324  GRN_LOG(ctx, GRN_LOG_CRIT, "deadlock detected! in grn_io_seg_expire(%p, %u, %u)", io, segno, nref);
1326  }
1327  } else {
1328  GRN_ATOMIC_ADD_EX(pnref, GRN_IO_MAX_REF, nref);
1329  if (nref > 1) {
1330  GRN_ATOMIC_ADD_EX(pnref, -(GRN_IO_MAX_REF + 1), nref);
1331  GRN_FUTEX_WAKE(pnref);
1332  if (retry >= GRN_IO_MAX_RETRY) {
1333  GRN_LOG(ctx, GRN_LOG_CRIT, "deadlock detected!! in grn_io_seg_expire(%p, %u, %u)", io,
1334  segno, nref);
1336  }
1337  } else {
1338  uint32_t nmaps;
1339  GRN_MUNMAP(&grn_gctx, &info->fmo, info->map, io->header->segment_size);
1340  info->map = NULL;
1341  GRN_ATOMIC_ADD_EX(pnref, -(GRN_IO_MAX_REF + 1), nref);
1342  GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
1343  GRN_FUTEX_WAKE(pnref);
1344  return GRN_SUCCESS;
1345  }
1346  }
1347  if (retry >= nretry) { return GRN_RESOURCE_DEADLOCK_AVOIDED; }
1348  GRN_FUTEX_WAIT(pnref);
1349  }
1350 }
1351 
1352 uint32_t
1353 grn_io_expire(grn_ctx *ctx, grn_io *io, int count_thresh, uint32_t limit)
1354 {
1355  uint32_t m, n = 0, ln = io->nmaps;
1356  switch ((io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
1357  case GRN_IO_EXPIRE_GTICK :
1358  {
1359  uint32_t nref, nmaps, *pnref = &io->nref;
1360  GRN_ATOMIC_ADD_EX(pnref, 1, nref);
1361  if (!nref && grn_gtick - io->count > count_thresh) {
1362  uint32_t i = io->header->n_arrays;
1363  grn_io_mapinfo *info = io->maps;
1364  grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
1365  while (i--) {
1366  memset(io->ainfo[i].addrs, 0, sizeof(void *) * array_specs[i].max_n_segments);
1367  }
1368  for (m = io->max_map_seg; m; info++, m--) {
1369  if (info->map) {
1370  GRN_MUNMAP(&grn_gctx, &info->fmo, info->map, io->header->segment_size);
1371  info->map = NULL;
1372  info->nref = 0;
1373  info->count = grn_gtick;
1374  GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
1375  n++;
1376  }
1377  }
1378  }
1379  GRN_ATOMIC_ADD_EX(pnref, -1, nref);
1380  }
1381  break;
1382  case GRN_IO_EXPIRE_SEGMENT :
1383  for (m = io->max_map_seg; n < limit && m; m--) {
1384  if (!grn_io_seg_expire(ctx, io, m, 0)) { n++; }
1385  }
1386  break;
1388  {
1389  grn_io_mapinfo *info = io->maps;
1390  for (m = io->max_map_seg; n < limit && m; info++, m--) {
1391  if (info->map && (grn_gtick - info->count) > count_thresh) {
1392  uint32_t nmaps, nref, *pnref = &info->nref;
1393  GRN_ATOMIC_ADD_EX(pnref, 1, nref);
1394  if (!nref && info->map && (grn_gtick - info->count) > count_thresh) {
1395  GRN_MUNMAP(&grn_gctx, &info->fmo, info->map, io->header->segment_size);
1396  GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
1397  info->map = NULL;
1398  info->count = grn_gtick;
1399  n++;
1400  }
1401  GRN_ATOMIC_ADD_EX(pnref, -1, nref);
1402  }
1403  }
1404  }
1405  break;
1406  }
1407  if (n) {
1408  GRN_LOG(ctx, GRN_LOG_INFO, "<%p:%x> expired i=%p max=%d (%d/%d)",
1409  ctx, grn_gtick, io, io->max_map_seg, n, ln);
1410  }
1411  return n;
1412 }
1413 
1414 static uint32_t
1415 grn_expire_(grn_ctx *ctx, int count_thresh, uint32_t limit)
1416 {
1417  uint32_t n = 0;
1418  grn_io *io;
1419  GRN_HASH_EACH(ctx, grn_gctx.impl->ios, id, NULL, NULL, (void **)&io, {
1420  grn_plugin_close(ctx, id);
1421  n += grn_io_expire(ctx, io, count_thresh, limit);
1422  if (n >= limit) { break; }
1423  });
1424  return n;
1425 }
1426 
1427 uint32_t
1428 grn_expire(grn_ctx *ctx, int count_thresh, uint32_t limit)
1429 {
1430  grn_ctx *c;
1431  uint32_t n = 0;
1432  CRITICAL_SECTION_ENTER(grn_glock);
1433  if (grn_gtick) {
1434  for (c = grn_gctx.next;; c = ctx->next) {
1435  if (c == &grn_gctx) {
1436  CRITICAL_SECTION_LEAVE(grn_glock);
1437  n = grn_expire_(ctx, count_thresh, limit);
1438  CRITICAL_SECTION_ENTER(grn_glock);
1439  break;
1440  }
1441  if ((c->seqno & 1) && (c->seqno == c->seqno2)) { break; }
1442  }
1443  }
1444  grn_gtick++;
1445  for (c = grn_gctx.next; c != &grn_gctx; c = ctx->next) { c->seqno2 = c->seqno; }
1446  CRITICAL_SECTION_LEAVE(grn_glock);
1447  return n;
1448 }
1449 
1450 void *
1451 grn_io_anon_map(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length)
1452 {
1453  return (mi->map = GRN_MMAP(ctx, &mi->fmo, NULL, 0, length));
1454 }
1455 
1456 void
1457 grn_io_anon_unmap(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length)
1458 {
1459  /* support WIN32 */
1460 #ifdef WIN32
1461  return GRN_FREE(mi->map);
1462 #endif
1463  GRN_MUNMAP(ctx, &mi->fmo, mi->map, length);
1464 }
1465 
1466 grn_rc
1467 grn_io_lock(grn_ctx *ctx, grn_io *io, int timeout)
1468 {
1469  static int _ncalls = 0, _ncolls = 0;
1470  uint32_t count, count_log_border = 1000;
1471  _ncalls++;
1472  if (!io) { return GRN_INVALID_ARGUMENT; }
1473  for (count = 0;; count++) {
1474  uint32_t lock;
1475  GRN_ATOMIC_ADD_EX(io->lock, 1, lock);
1476  if (lock) {
1477  GRN_ATOMIC_ADD_EX(io->lock, -1, lock);
1478  if (count == count_log_border) {
1479  GRN_LOG(ctx, GRN_LOG_NOTICE,
1480  "io(%s) collisions(%d/%d): lock failed %d times",
1481  io->path, _ncolls, _ncalls, count_log_border);
1482  }
1483  if (!timeout || (timeout > 0 && timeout == count)) {
1484  GRN_LOG(ctx, GRN_LOG_WARNING,
1485  "[DB Locked] time out(%d): io(%s) collisions(%d/%d)",
1486  timeout, io->path, _ncolls, _ncalls);
1487  break;
1488  }
1489  if (!(++_ncolls % 1000000) && (_ncolls > _ncalls)) {
1490  if (_ncolls < 0 || _ncalls < 0) {
1491  _ncolls = 0; _ncalls = 0;
1492  } else {
1493  GRN_LOG(ctx, GRN_LOG_NOTICE,
1494  "io(%s) collisions(%d/%d)", io->path, _ncolls, _ncalls);
1495  }
1496  }
1497  grn_nanosleep(1000000);
1498  continue;
1499  }
1500  return GRN_SUCCESS;
1501  }
1502  ERR(GRN_RESOURCE_DEADLOCK_AVOIDED, "grn_io_lock failed");
1503  return ctx->rc;
1504 }
1505 
1506 void
1508 {
1509  if (io) {
1510  uint32_t lock;
1511  GRN_ATOMIC_ADD_EX(io->lock, -1, lock);
1512  }
1513 }
1514 
1515 void
1517 {
1518  if (io) { *io->lock = 0; }
1519 }
1520 
1521 uint32_t
1523 {
1524  return io ? *io->lock : 0;
1525 }
1526 
1529 static size_t mmap_size = 0;
1530 
1531 #ifdef WIN32
1532 
1533 #ifdef WIN32_FMO_EACH
1534 
1535 inline static grn_rc
1536 grn_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags, size_t maxsize)
1537 {
1538  if ((flags & O_CREAT)) {
1539  DWORD dwCreationDisposition;
1540  if (flags & O_EXCL) {
1541  dwCreationDisposition = CREATE_NEW;
1542  } else {
1543  dwCreationDisposition = OPEN_ALWAYS;
1544  }
1545  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1546  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1547  dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
1548  if (fi->fh == INVALID_HANDLE_VALUE) {
1549  SERR("CreateFile");
1550  return ctx->rc;
1551  }
1552  goto exit;
1553  }
1554  if ((flags & O_TRUNC)) {
1555  CloseHandle(fi->fh);
1556  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1557  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1558  TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1559  if (fi->fh == INVALID_HANDLE_VALUE) {
1560  SERR("CreateFile");
1561  return ctx->rc;
1562  }
1563  goto exit;
1564  }
1565  /* O_RDWR only */
1566  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1567  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1568  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1569  if (fi->fh == INVALID_HANDLE_VALUE) {
1570  SERR("CreateFile");
1571  return ctx->rc;
1572  }
1573 exit:
1574  CRITICAL_SECTION_INIT(fi->cs);
1575  return GRN_SUCCESS;
1576 }
1577 
1578 inline static void *
1579 grn_mmap(grn_ctx *ctx, HANDLE *fmo, fileinfo *fi, off_t offset, size_t length)
1580 {
1581  void *res;
1582  if (!fi) {
1583  if(fmo) {
1584  *fmo = (HANDLE)0;
1585  }
1586  return GRN_GCALLOC(length);
1587  }
1588  /* CRITICAL_SECTION_ENTER(fi->cs); */
1589  /* try to create fmo */
1590  *fmo = CreateFileMapping(fi->fh, NULL, PAGE_READWRITE, 0, offset + length, NULL);
1591  if (!*fmo) { return NULL; }
1592  res = MapViewOfFile(*fmo, FILE_MAP_WRITE, 0, (DWORD)offset, (SIZE_T)length);
1593  if (!res) {
1594  MERR("MapViewOfFile failed #%d <%zu>", GetLastError(), mmap_size);
1595  return NULL;
1596  }
1597  /* CRITICAL_SECTION_LEAVE(fi->cs); */
1598  mmap_size += length;
1599  return res;
1600 }
1601 
1602 inline static int
1603 grn_munmap(grn_ctx *ctx, HANDLE *fmo, void *start, size_t length)
1604 {
1605  int r = 0;
1606  if (!fmo) {
1607  GRN_FREE(start);
1608  }
1609  if (*fmo) {
1610  if (UnmapViewOfFile(start)) {
1611  mmap_size -= length;
1612  } else {
1613  SERR("UnmapViewOfFile");
1614  GRN_LOG(ctx, GRN_LOG_ERROR, "UnmapViewOfFile(%p,%d) failed <%zu>", start, length, mmap_size);
1615  r = -1;
1616  }
1617  if (!CloseHandle(*fmo)) {
1618  SERR("CloseHandle");
1619  GRN_LOG(ctx, GRN_LOG_ERROR, "CloseHandle(%p,%d) failed <%zu>", start, length, mmap_size);
1620  }
1621  *fmo = NULL;
1622  } else {
1623  GRN_FREE(start);
1624  }
1625  return r;
1626 }
1627 
1628 inline static grn_rc
1629 grn_close(grn_ctx *ctx, fileinfo *fi)
1630 {
1631  if (fi->fmo != NULL) {
1632  GRN_LOG(ctx, GRN_LOG_ALERT, "file mapping object exists");
1633  }
1634  if (fi->fh != INVALID_HANDLE_VALUE) {
1635  CloseHandle(fi->fh);
1636  CRITICAL_SECTION_FIN(fi->cs);
1637  fi->fh = INVALID_HANDLE_VALUE;
1638  }
1639  return GRN_SUCCESS;
1640 }
1641 
1642 #else /* WIN32_FMO_EACH */
1643 inline static grn_rc
1644 grn_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags, size_t maxsize)
1645 {
1646  /* may be wrong if flags is just only O_RDWR */
1647  if ((flags & O_CREAT)) {
1648  DWORD dwCreationDisposition;
1649  if (flags & O_EXCL) {
1650  dwCreationDisposition = CREATE_NEW;
1651  } else {
1652  dwCreationDisposition = OPEN_ALWAYS;
1653  }
1654  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1655  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1656  dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
1657  if (fi->fh == INVALID_HANDLE_VALUE) {
1658  SERR("CreateFile");
1659  return ctx->rc;
1660  }
1661  goto exit;
1662  }
1663  if ((flags & O_TRUNC)) {
1664  CloseHandle(fi->fh);
1665  /* unable to assign OPEN_ALWAYS and TRUNCATE_EXISTING at once */
1666  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1667  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1668  TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1669  if (fi->fh == INVALID_HANDLE_VALUE) {
1670  SERR("CreateFile");
1671  return ctx->rc;
1672  }
1673  goto exit;
1674  }
1675  /* O_RDWR only */
1676  fi->fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
1677  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1678  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1679  if (fi->fh == INVALID_HANDLE_VALUE) {
1680  SERR("CreateFile");
1681  return ctx->rc;
1682  }
1683 exit:
1684  /* signature may be wrong.. */
1685  fi->fmo = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, NULL);
1686  /* open failed */
1687  if (fi->fmo == NULL) {
1688  // flock
1689  /* retry to open */
1690  fi->fmo = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, NULL);
1691  /* failed again */
1692  if (fi->fmo == NULL) {
1693  /* try to create fmo */
1694  fi->fmo = CreateFileMapping(fi->fh, NULL, PAGE_READWRITE, 0, GRN_IO_FILE_SIZE, NULL);
1695  }
1696  // funlock
1697  }
1698  if (fi->fmo != NULL) {
1699  if (GetLastError() != ERROR_ALREADY_EXISTS ) {
1700  CRITICAL_SECTION_INIT(fi->cs);
1701  return GRN_SUCCESS;
1702  } else {
1703  GRN_LOG(ctx, GRN_LOG_ERROR, "fmo object already exists! handle=%d", fi->fh);
1704  CloseHandle(fi->fmo);
1705  }
1706  } else {
1707  GRN_LOG(ctx, GRN_LOG_ALERT, "failed to get FileMappingObject #%d", GetLastError());
1708  }
1709  CloseHandle(fi->fh);
1710  SERR("OpenFileMapping");
1711  return ctx->rc;
1712 }
1713 
1714 inline static void *
1715 grn_mmap(grn_ctx *ctx, fileinfo *fi, off_t offset, size_t length)
1716 {
1717  void *res;
1718  if (!fi) { return GRN_GCALLOC(length); }
1719  /* file must be exceeded to GRN_IO_FILE_SIZE when FileMappingObject created.
1720  and, after fmo created, it's not allowed to expand the size of file.
1721  DWORD tail = (DWORD)(offset + length);
1722  DWORD filesize = GetFileSize(fi->fh, NULL);
1723  if (filesize < tail) {
1724  if (SetFilePointer(fi->fh, tail, NULL, FILE_BEGIN) != tail) {
1725  grn_log("SetFilePointer failed");
1726  return NULL;
1727  }
1728  if (!SetEndOfFile(fi->fh)) {
1729  grn_log("SetEndOfFile failed");
1730  return NULL;
1731  }
1732  filesize = tail;
1733  }
1734  */
1735  res = MapViewOfFile(fi->fmo, FILE_MAP_WRITE, 0, (DWORD)offset, (SIZE_T)length);
1736  if (!res) {
1737  MERR("MapViewOfFile failed #%d <%zu>", GetLastError(), mmap_size);
1738  return NULL;
1739  }
1740  mmap_size += length;
1741  return res;
1742 }
1743 
1744 inline static int
1745 grn_munmap(grn_ctx *ctx, void *start, size_t length)
1746 {
1747  if (UnmapViewOfFile(start)) {
1748  mmap_size -= length;
1749  return 0;
1750  } else {
1751  SERR("UnmapViewOfFile");
1752  GRN_LOG(ctx, GRN_LOG_ERROR, "UnmapViewOfFile(%p,%d) failed <%zu>", start, length, mmap_size);
1753  return -1;
1754  }
1755 }
1756 
1757 inline static grn_rc
1758 grn_close(grn_ctx *ctx, fileinfo *fi)
1759 {
1760  if (fi->fmo != NULL) {
1761  CloseHandle(fi->fmo);
1762  fi->fmo = NULL;
1763  }
1764  if (fi->fh != INVALID_HANDLE_VALUE) {
1765  CloseHandle(fi->fh);
1766  CRITICAL_SECTION_FIN(fi->cs);
1767  fi->fh = INVALID_HANDLE_VALUE;
1768  }
1769  return GRN_SUCCESS;
1770 }
1771 #endif /* WIN32_FMO_EACH */
1772 
1773 inline static void
1774 grn_fileinfo_init(fileinfo *fis, int nfis)
1775 {
1776  for (; nfis--; fis++) {
1777  fis->fh = INVALID_HANDLE_VALUE;
1778  fis->fmo = NULL;
1779  }
1780 }
1781 
1782 inline static int
1783 grn_opened(fileinfo *fi)
1784 {
1785  return fi->fh != INVALID_HANDLE_VALUE;
1786 }
1787 
1788 inline static int
1789 grn_msync(grn_ctx *ctx, void *start, size_t length)
1790 {
1791  /* return value may be wrong... */
1792  return FlushViewOfFile(start, length);
1793 }
1794 
1795 inline static grn_rc
1796 grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
1797 {
1798  DWORD r, len;
1799  CRITICAL_SECTION_ENTER(fi->cs);
1800  r = SetFilePointer(fi->fh, offset, NULL, FILE_BEGIN);
1801  if (r == INVALID_SET_FILE_POINTER) {
1802  SERR("SetFilePointer");
1803  } else {
1804  if (!ReadFile(fi->fh, buf, (DWORD)count, &len, NULL)) {
1805  SERR("ReadFile");
1806  } else if (len != count) {
1807  /* todo : should retry ? */
1808  ERR(GRN_INPUT_OUTPUT_ERROR, "ReadFile %d != %d", count, len);
1809  }
1810  }
1811  CRITICAL_SECTION_LEAVE(fi->cs);
1812  return ctx->rc;
1813 }
1814 
1815 inline static grn_rc
1816 grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
1817 {
1818  DWORD r, len;
1819  CRITICAL_SECTION_ENTER(fi->cs);
1820  r = SetFilePointer(fi->fh, offset, NULL, FILE_BEGIN);
1821  if (r == INVALID_SET_FILE_POINTER) {
1822  SERR("SetFilePointer");
1823  } else {
1824  if (!WriteFile(fi->fh, buf, (DWORD)count, &len, NULL)) {
1825  SERR("WriteFile");
1826  } else if (len != count) {
1827  /* todo : should retry ? */
1828  ERR(GRN_INPUT_OUTPUT_ERROR, "WriteFile %d != %d", count, len);
1829  }
1830  }
1831  CRITICAL_SECTION_LEAVE(fi->cs);
1832  return ctx->rc;
1833 }
1834 
1835 #else /* WIN32 */
1836 
1837 inline static grn_rc
1838 grn_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags, size_t maxsize)
1839 {
1840  struct stat st;
1841  if ((fi->fd = GRN_OPEN(path, flags, 0666)) == -1) {
1842  SERR(path);
1843  return ctx->rc;
1844  }
1845  if (fstat(fi->fd, &st) == -1) {
1846  SERR(path);
1847  return ctx->rc;
1848  }
1849  fi->dev = st.st_dev;
1850  fi->inode = st.st_ino;
1851  return GRN_SUCCESS;
1852 }
1853 
1854 inline static void
1855 grn_fileinfo_init(fileinfo *fis, int nfis)
1856 {
1857  for (; nfis--; fis++) { fis->fd = -1; }
1858 }
1859 
1860 inline static int
1861 grn_opened(fileinfo *fi)
1862 {
1863  return fi->fd != -1;
1864 }
1865 
1866 inline static grn_rc
1867 grn_close(grn_ctx *ctx, fileinfo *fi)
1868 {
1869  if (fi->fd != -1) {
1870  if (GRN_CLOSE(fi->fd) == -1) {
1871  SERR("close");
1872  return ctx->rc;
1873  }
1874  fi->fd = -1;
1875  }
1876  return GRN_SUCCESS;
1877 }
1878 
1879 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
1880 #define MAP_ANONYMOUS MAP_ANON
1881 #endif
1882 
1883 #include <sys/mman.h>
1884 
1885 inline static void *
1886 grn_mmap(grn_ctx *ctx, fileinfo *fi, off_t offset, size_t length)
1887 {
1888  void *res;
1889  int fd, flags;
1890  if (fi) {
1891  struct stat s;
1892  off_t tail = offset + length;
1893  fd = fi->fd;
1894  if ((fstat(fd, &s) == -1) || (s.st_size < tail && ftruncate(fd, tail) == -1)) {
1895  SERR("fstat");
1896  return NULL;
1897  }
1898  flags = MAP_SHARED;
1899  } else {
1900  fd = -1;
1901  flags = MAP_PRIVATE|MAP_ANONYMOUS;
1902  }
1903  res = mmap(NULL, length, PROT_READ|PROT_WRITE, flags, fd, offset);
1904  if (MAP_FAILED == res) {
1905  MERR("mmap(%" GRN_FMT_LLU ",%d,%" GRN_FMT_LLD ")=%s <%" GRN_FMT_LLU ">",
1906  (unsigned long long int)length, fd, (long long int)offset, strerror(errno),
1907  (unsigned long long int)mmap_size);
1908  return NULL;
1909  }
1910  mmap_size += length;
1911  return res;
1912 }
1913 
1914 #ifdef USE_FAIL_MALLOC
1915 inline static void *
1916 grn_fail_mmap(grn_ctx *ctx, fileinfo *fi, off_t offset, size_t length,
1917  const char* file, int line, const char *func)
1918 {
1919  if (grn_fail_malloc_check(length, file, line, func)) {
1920  return grn_mmap(ctx, fi, offset, length);
1921  } else {
1922  MERR("fail_mmap(%zu,%d,%" GRN_FMT_LLU ") (%s:%d@%s) <%zu>",
1923  length, fi ? fi->fd : 0, offset, file, line, func, mmap_size);
1924  return NULL;
1925  }
1926 }
1927 #endif /* USE_FAIL_MALLOC */
1928 
1929 inline static int
1930 grn_msync(grn_ctx *ctx, void *start, size_t length)
1931 {
1932  int r = msync(start, length, MS_SYNC);
1933  if (r == -1) { SERR("msync"); }
1934  return r;
1935 }
1936 
1937 inline static int
1938 grn_munmap(grn_ctx *ctx, void *start, size_t length)
1939 {
1940  int res;
1941  res = munmap(start, length);
1942  if (res) {
1943  SERR("munmap");
1944  GRN_LOG(ctx, GRN_LOG_ERROR, "munmap(%p,%" GRN_FMT_LLU ") failed <%" GRN_FMT_LLU ">",
1945  start, (unsigned long long int)length, (unsigned long long int)mmap_size);
1946  } else {
1947  mmap_size -= length;
1948  }
1949  return res;
1950 }
1951 
1952 inline static grn_rc
1953 grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
1954 {
1955  ssize_t r = pread(fi->fd, buf, count, offset);
1956  if (r != count) {
1957  if (r == -1) {
1958  SERR("pread");
1959  } else {
1960  /* todo : should retry ? */
1961  ERR(GRN_INPUT_OUTPUT_ERROR, "pread returned %" GRN_FMT_LLD " != %" GRN_FMT_LLU,
1962  (long long int)r, (unsigned long long int)count);
1963  }
1964  return ctx->rc;
1965  }
1966  return GRN_SUCCESS;
1967 }
1968 
1969 inline static grn_rc
1970 grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
1971 {
1972  ssize_t r = pwrite(fi->fd, buf, count, offset);
1973  if (r != count) {
1974  if (r == -1) {
1975  SERR("pwrite");
1976  } else {
1977  /* todo : should retry ? */
1978  ERR(GRN_INPUT_OUTPUT_ERROR, "pwrite returned %" GRN_FMT_LLD " != %" GRN_FMT_LLU,
1979  (long long int)r, (unsigned long long int)count);
1980  }
1981  return ctx->rc;
1982  }
1983  return GRN_SUCCESS;
1984 }
1985 
1986 #endif /* WIN32 */