Fix documentation of of chr's equivalent directive ZEB-672
[idzebra-moved-to-github.git] / bfile / commit.c
1 /* This file is part of the Zebra server.
2    Copyright (C) Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <assert.h>
25 #include <stdlib.h>
26
27 #include <idzebra/util.h>
28 #include <yaz/xmalloc.h>
29 #include "mfile.h"
30 #include "cfile.h"
31
32 #define CF_OPTIMIZE_COMMIT 0
33
34 static int log_level = 0;
35
36 #if CF_OPTIMIZE_COMMIT
37 struct map_cache_entity {
38     int from;
39     int to;
40 };
41
42 struct map_cache {
43     int max;
44     int no;
45
46     struct map_cache_entity *map;
47     char *buf;
48     CFile cf;
49 };
50
51 static struct map_cache *map_cache_init (CFile cf)
52 {
53     int mem_max = 2000000;
54     struct map_cache *m_p;
55
56     m_p = xmalloc (sizeof(*m_p));
57     m_p->cf = cf;
58     m_p->max = mem_max / cf->head.block_size;
59     m_p->buf = xmalloc (mem_max);
60     m_p->no = 0;
61     m_p->map = xmalloc (sizeof(*m_p->map) * m_p->max);
62     return m_p;
63 }
64
65 static int map_cache_cmp_from (const void *p1, const void *p2)
66 {
67     return ((struct map_cache_entity*) p1)->from -
68         ((struct map_cache_entity*) p2)->from;
69 }
70
71 static int map_cache_cmp_to(const void *p1, const void *p2)
72 {
73     return ((struct map_cache_entity*) p1)->to -
74         ((struct map_cache_entity*) p2)->to;
75 }
76
77 static int map_cache_flush(struct map_cache *m_p)
78 {
79     int i;
80
81     qsort (m_p->map, m_p->no, sizeof(*m_p->map), map_cache_cmp_from);
82     assert (m_p->no < 2 || m_p->map[0].from < m_p->map[1].from);
83     for (i = 0; i<m_p->no; i++)
84     {
85         if (mf_read(m_p->cf->block_mf, m_p->map[i].from, 0, 0,
86                     m_p->buf + i * m_p->cf->head.block_size) != 1)
87         {
88             yaz_log (YLOG_FATAL, "read commit block at position %d",
89                      m_p->map[i].from);
90             return -1;
91         }
92         m_p->map[i].from = i;
93     }
94     qsort (m_p->map, m_p->no, sizeof(*m_p->map), map_cache_cmp_to);
95     assert (m_p->no < 2 || m_p->map[0].to < m_p->map[1].to);
96     for (i = 0; i<m_p->no; i++)
97     {
98         if (mf_write(m_p->cf->rmf, m_p->map[i].to, 0, 0,
99                      m_p->buf + m_p->map[i].from * m_p->cf->head.block_size))
100             return -1;
101     }
102     m_p->no = 0;
103     return 0;
104 }
105
106 static int map_cache_del(struct map_cache *m_p)
107 {
108     int r = map_cache_flush(m_p);
109     xfree (m_p->map);
110     xfree (m_p->buf);
111     xfree (m_p);
112     return r;
113 }
114
115 static int map_cache_add(struct map_cache *m_p, int from, int to)
116 {
117     int i = m_p->no;
118
119     m_p->map[i].from = from;
120     m_p->map[i].to = to;
121     m_p->no = ++i;
122     if (i == m_p->max)
123         return map_cache_flush(m_p);
124     return 0;
125 }
126
127 /* CF_OPTIMIZE_COMMIT */
128 #endif
129
130 static int cf_commit_hash (CFile cf)
131 {
132     int r = 0;
133     int i;
134     zint bucket_no;
135     struct CFile_ph_bucket *p;
136 #if CF_OPTIMIZE_COMMIT
137     struct map_cache *m_p;
138 #endif
139
140 #if CF_OPTIMIZE_COMMIT
141     m_p = map_cache_init (cf);
142 #endif
143
144     p = (struct CFile_ph_bucket *) xmalloc (sizeof(*p));
145     bucket_no = cf->head.first_bucket;
146     for (; bucket_no < cf->head.next_bucket; bucket_no++)
147     {
148         if (mf_read (cf->hash_mf, bucket_no, 0, 0, p) != 1)
149         {
150             yaz_log (YLOG_FATAL, "read commit hash");
151             r = -1;
152             goto out;
153         }
154         for (i = 0; i<HASH_BUCKET && p->vno[i]; i++)
155         {
156 #if CF_OPTIMIZE_COMMIT
157             if (map_cache_add(m_p, p->vno[i], p->no[i]))
158             {
159                 r = -1;
160                 goto out;
161             }
162 #else
163             if (mf_read(cf->block_mf, p->vno[i], 0, 0, cf->iobuf) != 1)
164             {
165                 yaz_log (YLOG_FATAL, "read commit block");
166                 r = -1;
167                 goto out;
168             }
169             if (mf_write(cf->rmf, p->no[i], 0, 0, cf->iobuf))
170             {
171                 yaz_log (YLOG_FATAL, "write commit block");
172                 r = -1;
173                 goto out;
174             }
175 #endif
176         }
177     }
178  out:
179 #if CF_OPTIMIZE_COMMIT
180     if (map_cache_del(m_p))
181         r = -1;
182 #endif
183     xfree(p);
184     return r;
185 }
186
187 static int cf_commit_flat(CFile cf)
188 {
189     zint *fp;
190     zint hno;
191     int i;
192     int r = 0;
193     zint vno = 0;
194
195 #if CF_OPTIMIZE_COMMIT
196     struct map_cache *m_p;
197 #endif
198
199
200 #if CF_OPTIMIZE_COMMIT
201     m_p = map_cache_init (cf);
202 #endif
203     fp = (zint *) xmalloc (HASH_BSIZE);
204     for (hno = cf->head.next_bucket; hno < cf->head.flat_bucket; hno++)
205     {
206         for (i = 0; i < (int) (HASH_BSIZE/sizeof(zint)); i++)
207             fp[i] = 0;
208         if (!mf_read (cf->hash_mf, hno, 0, 0, fp) &&
209             hno != cf->head.flat_bucket-1)
210         {
211             yaz_log (YLOG_FATAL, "read index block hno=" ZINT_FORMAT
212                      " (" ZINT_FORMAT "-" ZINT_FORMAT ") commit",
213                      hno, cf->head.next_bucket, cf->head.flat_bucket-1);
214             r = -1;
215             goto out;
216         }
217         for (i = 0; i < (int) (HASH_BSIZE/sizeof(zint)); i++)
218         {
219             if (fp[i])
220             {
221 #if CF_OPTIMIZE_COMMIT
222                 if (map_cache_add(m_p, fp[i], vno))
223                 {
224                     r = -1;
225                     goto out;
226                 }
227 #else
228                 if (mf_read (cf->block_mf, fp[i], 0, 0, cf->iobuf) != 1)
229                 {
230                     yaz_log (YLOG_FATAL, "read data block hno=" ZINT_FORMAT " (" ZINT_FORMAT "-" ZINT_FORMAT ") "
231                              "i=%d commit block at " ZINT_FORMAT " (->" ZINT_FORMAT")",
232                              hno, cf->head.next_bucket, cf->head.flat_bucket-1,
233                              i, fp[i], vno);
234                     r = -1;
235                     goto out;
236                 }
237                 if (mf_write(cf->rmf, vno, 0, 0, cf->iobuf))
238                 {
239                     r = -1;
240                     goto out;
241                 }
242 #endif
243             }
244             vno++;
245         }
246     }
247  out:
248 #if CF_OPTIMIZE_COMMIT
249     if (map_cache_del(m_p))
250         r = -1;
251 #endif
252     yaz_log(log_level, "cf_commit_flat r=%d", r);
253     xfree(fp);
254     return r;
255 }
256
257 int cf_commit(CFile cf)
258 {
259     if (cf->bucket_in_memory)
260     {
261         yaz_log(YLOG_FATAL, "cf_commit: dirty cache");
262         return -1;
263     }
264     yaz_log(log_level, "cf_commit: state=%d", cf->head.state);
265     if (cf->head.state == CFILE_STATE_HASH)
266         return cf_commit_hash(cf);
267     else if (cf->head.state == CFILE_STATE_FLAT)
268         return cf_commit_flat(cf);
269     else
270     {
271         yaz_log(YLOG_FATAL, "cf_commit: bad state=%d", cf->head.state);
272         return -1;
273     }
274 }
275
276 /*
277  * Local variables:
278  * c-basic-offset: 4
279  * c-file-style: "Stroustrup"
280  * indent-tabs-mode: nil
281  * End:
282  * vim: shiftwidth=4 tabstop=8 expandtab
283  */
284