RPM: store libs in %{_libdir}
[idzebra-moved-to-github.git] / bfile / commit.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2011 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     int hash_bytes;
136     struct CFile_ph_bucket *p;
137 #if CF_OPTIMIZE_COMMIT
138     struct map_cache *m_p;
139 #endif
140
141 #if CF_OPTIMIZE_COMMIT
142     m_p = map_cache_init (cf);
143 #endif
144
145     p = (struct CFile_ph_bucket *) xmalloc (sizeof(*p));
146     hash_bytes = cf->head.hash_size * sizeof(zint);
147     bucket_no = cf->head.first_bucket;
148     for (; bucket_no < cf->head.next_bucket; bucket_no++)
149     {
150         if (mf_read (cf->hash_mf, bucket_no, 0, 0, p) != 1)
151         {
152             yaz_log (YLOG_FATAL, "read commit hash");
153             r = -1;
154             goto out;
155         }
156         for (i = 0; i<HASH_BUCKET && p->vno[i]; i++)
157         {
158 #if CF_OPTIMIZE_COMMIT
159             if (map_cache_add(m_p, p->vno[i], p->no[i]))
160             {
161                 r = -1;
162                 goto out;
163             }
164 #else
165             if (mf_read(cf->block_mf, p->vno[i], 0, 0, cf->iobuf) != 1)
166             {
167                 yaz_log (YLOG_FATAL, "read commit block");
168                 r = -1;
169                 goto out;
170             }
171             if (mf_write(cf->rmf, p->no[i], 0, 0, cf->iobuf))
172             {
173                 yaz_log (YLOG_FATAL, "write commit block");
174                 r = -1;
175                 goto out;
176             }
177 #endif
178         }
179     }
180  out:
181 #if CF_OPTIMIZE_COMMIT
182     if (map_cache_del(m_p))
183         r = -1;
184 #endif
185     xfree(p);
186     return r;
187 }
188
189 static int cf_commit_flat(CFile cf)
190 {
191     zint *fp;
192     zint hno;
193     int i;
194     int r = 0;
195     zint vno = 0;
196
197 #if CF_OPTIMIZE_COMMIT
198     struct map_cache *m_p;
199 #endif
200
201
202 #if CF_OPTIMIZE_COMMIT
203     m_p = map_cache_init (cf);
204 #endif
205     fp = (zint *) xmalloc (HASH_BSIZE);
206     for (hno = cf->head.next_bucket; hno < cf->head.flat_bucket; hno++)
207     {
208         for (i = 0; i < (int) (HASH_BSIZE/sizeof(zint)); i++)
209             fp[i] = 0;
210         if (!mf_read (cf->hash_mf, hno, 0, 0, fp) &&
211             hno != cf->head.flat_bucket-1)
212         {
213             yaz_log (YLOG_FATAL, "read index block hno=" ZINT_FORMAT
214                      " (" ZINT_FORMAT "-" ZINT_FORMAT ") commit",
215                      hno, cf->head.next_bucket, cf->head.flat_bucket-1);
216             r = -1;
217             goto out;
218         }
219         for (i = 0; i < (int) (HASH_BSIZE/sizeof(zint)); i++)
220         {
221             if (fp[i])
222             {
223 #if CF_OPTIMIZE_COMMIT
224                 if (map_cache_add(m_p, fp[i], vno))
225                 {
226                     r = -1;
227                     goto out;
228                 }
229 #else
230                 if (mf_read (cf->block_mf, fp[i], 0, 0, cf->iobuf) != 1)
231                 {
232                     yaz_log (YLOG_FATAL, "read data block hno=" ZINT_FORMAT " (" ZINT_FORMAT "-" ZINT_FORMAT ") "
233                              "i=%d commit block at " ZINT_FORMAT " (->" ZINT_FORMAT")",
234                              hno, cf->head.next_bucket, cf->head.flat_bucket-1,
235                              i, fp[i], vno);
236                     r = -1;
237                     goto out;
238                 }
239                 if (mf_write(cf->rmf, vno, 0, 0, cf->iobuf))
240                 {
241                     r = -1;
242                     goto out;
243                 }
244 #endif
245             }
246             vno++;
247         }
248     }
249  out:
250 #if CF_OPTIMIZE_COMMIT
251     if (map_cache_del(m_p))
252         r = -1;
253 #endif
254     yaz_log(log_level, "cf_commit_flat r=%d", r);
255     xfree(fp);
256     return r;
257 }
258
259 int cf_commit(CFile cf)
260 {
261     if (cf->bucket_in_memory)
262     {
263         yaz_log(YLOG_FATAL, "cf_commit: dirty cache");
264         return -1;
265     }
266     yaz_log(log_level, "cf_commit: state=%d", cf->head.state);
267     if (cf->head.state == CFILE_STATE_HASH)
268         return cf_commit_hash(cf);
269     else if (cf->head.state == CFILE_STATE_FLAT)
270         return cf_commit_flat(cf);
271     else
272     {
273         yaz_log(YLOG_FATAL, "cf_commit: bad state=%d", cf->head.state);
274         return -1;
275     }
276 }
277
278 /*
279  * Local variables:
280  * c-basic-offset: 4
281  * c-file-style: "Stroustrup"
282  * indent-tabs-mode: nil
283  * End:
284  * vim: shiftwidth=4 tabstop=8 expandtab
285  */
286