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