Fixed but in cf_commit_flat.
[idzebra-moved-to-github.git] / bfile / commit.c
1 /*
2  * Copyright (C) 1995-1998, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: commit.c,v $
7  * Revision 1.14  1998-08-07 15:07:16  adam
8  * Fixed but in cf_commit_flat.
9  *
10  * Revision 1.13  1996/10/29 13:56:16  adam
11  * Include of zebrautl.h instead of alexutil.h.
12  *
13  * Revision 1.12  1996/04/24 13:29:16  adam
14  * Work on optimized on commit operation.
15  *
16  * Revision 1.11  1996/04/23  12:36:41  adam
17  * Started work on more efficient commit operation.
18  *
19  * Revision 1.10  1996/04/18  16:02:56  adam
20  * Changed logging a bit.
21  * Removed warning message when commiting flat shadow files.
22  *
23  * Revision 1.9  1996/04/12  07:01:57  adam
24  * Yet another bug fix (next_block was initialized to 0; now set to 1).
25  *
26  * Revision 1.8  1996/02/07 14:03:49  adam
27  * Work on flat indexed shadow files.
28  *
29  * Revision 1.7  1996/02/07  10:08:46  adam
30  * Work on flat shadow (not finished yet).
31  *
32  * Revision 1.6  1995/12/15  12:36:53  adam
33  * Moved hash file information to union.
34  * Renamed commit files.
35  *
36  * Revision 1.5  1995/12/12  15:57:55  adam
37  * Implemented mf_unlink. cf_unlink uses mf_unlink.
38  *
39  * Revision 1.4  1995/12/11  09:03:55  adam
40  * New function: cf_unlink.
41  * New member of commit file head: state (0) deleted, (1) hash file.
42  *
43  * Revision 1.3  1995/12/01  16:24:29  adam
44  * Commit files use separate meta file area.
45  *
46  * Revision 1.2  1995/12/01  11:37:24  adam
47  * Cached/commit files implemented as meta-files.
48  *
49  * Revision 1.1  1995/11/30  08:33:13  adam
50  * Started work on commit facility.
51  *
52  */
53
54 #include <assert.h>
55 #include <stdlib.h>
56
57 #include <zebrautl.h>
58 #include <mfile.h>
59 #include "cfile.h"
60
61 #define CF_OPTIMIZE_COMMIT 0
62
63 void cf_unlink (CFile cf)
64 {
65     if (cf->bucket_in_memory)
66     {
67         logf (LOG_FATAL, "Cannot unlink potential dirty cache");
68         exit (1);
69     }
70     cf->head.state = 0;
71     cf->dirty = 1;
72     mf_unlink (cf->block_mf);
73     mf_unlink (cf->hash_mf);
74 }
75
76
77 #if CF_OPTIMIZE_COMMIT
78 struct map_cache_entity {
79     int from;
80     int to;
81 };
82
83 struct map_cache {
84     int max;
85     int no;
86
87     struct map_cache_entity *map;
88     char *buf;
89     CFile cf;
90 };
91
92 static struct map_cache *map_cache_init (CFile cf)
93 {
94     int mem_max = 2000000;
95     struct map_cache *m_p;
96
97     m_p = xmalloc (sizeof(*m_p));
98     m_p->cf = cf;
99     m_p->max = mem_max / cf->head.block_size;
100     m_p->buf = xmalloc (mem_max);
101     m_p->no = 0;
102     m_p->map = xmalloc (sizeof(*m_p->map) * m_p->max);
103     return m_p;
104 }
105
106 static int map_cache_cmp_from (const void *p1, const void *p2)
107 {
108     return ((struct map_cache_entity*) p1)->from -
109         ((struct map_cache_entity*) p2)->from;
110 }
111
112 static int map_cache_cmp_to (const void *p1, const void *p2)
113 {
114     return ((struct map_cache_entity*) p1)->to -
115         ((struct map_cache_entity*) p2)->to;
116 }
117
118 static void map_cache_flush (struct map_cache *m_p)
119 {
120     int i;
121
122     qsort (m_p->map, m_p->no, sizeof(*m_p->map), map_cache_cmp_from);
123     assert (m_p->no < 2 || m_p->map[0].from < m_p->map[1].from);
124     for (i = 0; i<m_p->no; i++)
125     {
126         if (!mf_read (m_p->cf->block_mf, m_p->map[i].from, 0, 0,
127                       m_p->buf + i * m_p->cf->head.block_size))
128         {
129             logf (LOG_FATAL, "read commit block at position %d",
130                   m_p->map[i].from);
131             exit (1);
132         }
133         m_p->map[i].from = i;
134     }
135     qsort (m_p->map, m_p->no, sizeof(*m_p->map), map_cache_cmp_to);
136     assert (m_p->no < 2 || m_p->map[0].to < m_p->map[1].to);
137     for (i = 0; i<m_p->no; i++)
138     {
139         mf_write (m_p->cf->rmf, m_p->map[i].to, 0, 0,
140                   m_p->buf + m_p->map[i].from * m_p->cf->head.block_size);
141     }    
142     m_p->no = 0;
143 }
144
145 static void map_cache_del (struct map_cache *m_p)
146 {
147     map_cache_flush (m_p);
148     xfree (m_p->map);
149     xfree (m_p->buf);
150     xfree (m_p);
151 }
152
153 static void map_cache_add (struct map_cache *m_p, int from, int to)
154 {
155     int i = m_p->no;
156
157     m_p->map[i].from = from;
158     m_p->map[i].to = to;
159     m_p->no = ++i;
160     if (i == m_p->max)
161         map_cache_flush (m_p);
162 }
163
164 /* CF_OPTIMIZE_COMMIT */
165 #endif
166
167 static void cf_commit_hash (CFile cf)
168
169     int i, bucket_no;
170     int hash_bytes;
171     struct CFile_ph_bucket *p;
172 #if CF_OPTIMIZE_COMMIT
173     struct map_cache *m_p;
174 #endif
175
176 #if CF_OPTIMIZE_COMMIT
177     m_p = map_cache_init (cf);
178 #endif
179
180     p = xmalloc (sizeof(*p));
181     hash_bytes = cf->head.hash_size * sizeof(int);
182     bucket_no = cf->head.first_bucket;
183     for (; bucket_no < cf->head.next_bucket; bucket_no++)
184     {
185         if (!mf_read (cf->hash_mf, bucket_no, 0, 0, p))
186         {
187             logf (LOG_FATAL, "read commit hash");
188             exit (1);
189         }
190         for (i = 0; i<HASH_BUCKET && p->vno[i]; i++)
191         {
192 #if CF_OPTIMIZE_COMMIT
193             map_cache_add (m_p, p->vno[i], p->no[i]);
194 #else
195             if (!mf_read (cf->block_mf, p->vno[i], 0, 0, cf->iobuf))
196             {
197                 logf (LOG_FATAL, "read commit block");
198                 exit (1);
199             }
200             mf_write (cf->rmf, p->no[i], 0, 0, cf->iobuf);
201 #endif
202         }
203     }
204 #if CF_OPTIMIZE_COMMIT
205     map_cache_del (m_p);
206 #endif
207     xfree (p);
208 }
209
210 static void cf_commit_flat (CFile cf)
211 {
212     int *fp;
213     int hno;
214     int i, vno = 0;
215
216 #if CF_OPTIMIZE_COMMIT
217     struct map_cache *m_p;
218 #endif
219
220
221 #if CF_OPTIMIZE_COMMIT
222     m_p = map_cache_init (cf);
223 #endif
224     fp = xmalloc (HASH_BSIZE);
225     for (hno = cf->head.next_bucket; hno < cf->head.flat_bucket; hno++)
226     {
227         for (i = 0; i < (HASH_BSIZE/sizeof(int)); i++)
228             fp[i] = 0;
229         if (!mf_read (cf->hash_mf, hno, 0, 0, fp) &&
230             hno != cf->head.flat_bucket-1)
231         {
232             logf (LOG_FATAL, "read index block hno=%d (%d-%d) commit",
233                   hno, cf->head.next_bucket, cf->head.flat_bucket-1);
234         }
235         for (i = 0; i < (HASH_BSIZE/sizeof(int)); i++)
236         {
237             if (fp[i])
238             {
239 #if CF_OPTIMIZE_COMMIT
240                 map_cache_add (m_p, fp[i], vno);
241 #else
242                 if (!mf_read (cf->block_mf, fp[i], 0, 0, cf->iobuf))
243                 {
244                     logf (LOG_FATAL, "read data block hno=%d (%d-%d) "
245                                      "i=%d commit block at %d (->%d)",
246                           hno, cf->head.next_bucket, cf->head.flat_bucket-1,
247                           i, fp[i], vno);
248                     exit (1);
249                 }
250                 mf_write (cf->rmf, vno, 0, 0, cf->iobuf);
251
252 #endif
253             }
254             vno++;
255         }
256     }
257 #if CF_OPTIMIZE_COMMIT
258     map_cache_del (m_p);
259 #endif
260     xfree (fp);
261 }
262
263 void cf_commit (CFile cf)
264 {
265
266     if (cf->bucket_in_memory)
267     {
268         logf (LOG_FATAL, "Cannot commit potential dirty cache");
269         exit (1);
270     }
271     if (cf->head.state == 1)
272         cf_commit_hash (cf);
273     else if (cf->head.state == 2)
274         cf_commit_flat (cf);
275 }
276