Version 2.0.58
[idzebra-moved-to-github.git] / dict / drdwr.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
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #if HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <assert.h>
34
35 #include "dict-p.h"
36
37 void dict_pr_lru(Dict_BFile bf)
38 {
39     struct Dict_file_block *p;
40     for (p=bf->lru_back; p; p = p->lru_next)
41     {
42         printf(" %d", p->no);
43     }
44     printf("\n");
45     fflush(stdout);
46 }
47
48 static struct Dict_file_block *find_block(Dict_BFile bf, int no)
49 {
50     struct Dict_file_block *p;
51
52     for (p=bf->hash_array[no% bf->hash_size]; p; p=p->h_next)
53         if (p->no == no)
54             break;
55     return p;
56 }
57
58 static void release_block(Dict_BFile bf, struct Dict_file_block *p)
59 {
60     assert(p);
61
62     /* remove from lru queue */
63     if (p->lru_prev)
64         p->lru_prev->lru_next = p->lru_next;
65     else
66         bf->lru_back = p->lru_next;
67     if (p->lru_next)
68         p->lru_next->lru_prev = p->lru_prev;
69     else
70         bf->lru_front = p->lru_prev;
71
72     /* remove from hash chain */
73     *p->h_prev = p->h_next;
74     if (p->h_next)
75         p->h_next->h_prev = p->h_prev;
76
77     /* move to list of free blocks */
78     p->h_next = bf->free_list;
79     bf->free_list = p;
80 }
81
82 void dict_bf_flush_blocks(Dict_BFile bf, int no_to_flush)
83 {
84     struct Dict_file_block *p;
85     int i;
86     for (i=0; i != no_to_flush && bf->lru_back; i++)
87     {
88         p = bf->lru_back;
89         if (p->dirty)
90         {
91             if (!bf->compact_flag)
92                 bf_write(bf->bf, p->no, 0, 0, p->data);
93             else
94             {
95                 int effective_block = p->no / bf->block_size;
96                 int effective_offset = p->no -
97                     effective_block * bf->block_size;
98                 int remain = bf->block_size - effective_offset;
99
100                 if (remain >= p->nbytes)
101                 {
102                     bf_write(bf->bf, effective_block, effective_offset,
103                              p->nbytes, p->data);
104 #if 0
105                     yaz_log(YLOG_LOG, "bf_write no=%d offset=%d size=%d",
106                             effective_block, effective_offset,
107                             p->nbytes);
108 #endif
109
110                 }
111                 else
112                 {
113 #if 0
114                     yaz_log(YLOG_LOG, "bf_write1 no=%d offset=%d size=%d",
115                             effective_block, effective_offset,
116                             remain);
117 #endif
118                     bf_write(bf->bf, effective_block, effective_offset,
119                              remain, p->data);
120 #if 0
121                     yaz_log(YLOG_LOG, "bf_write2 no=%d offset=%d size=%d",
122                             effective_block+1, 0, p->nbytes - remain);
123 #endif
124                     bf_write(bf->bf, effective_block+1, 0,
125                              p->nbytes - remain, (char*)p->data + remain);
126                 }
127             }
128         }
129         release_block(bf, p);
130     }
131 }
132
133 static struct Dict_file_block *alloc_block(Dict_BFile bf, int no)
134 {
135     struct Dict_file_block *p, **pp;
136
137     if (!bf->free_list)
138         dict_bf_flush_blocks(bf, 1);
139     assert(bf->free_list);
140     p = bf->free_list;
141     bf->free_list = p->h_next;
142     p->dirty = 0;
143     p->no = no;
144
145     /* insert at front in lru chain */
146     p->lru_next = NULL;
147     p->lru_prev = bf->lru_front;
148     if (bf->lru_front)
149         bf->lru_front->lru_next = p;
150     else
151         bf->lru_back = p;
152     bf->lru_front = p;
153
154     /* insert in hash chain */
155     pp = bf->hash_array + (no % bf->hash_size);
156     p->h_next = *pp;
157     p->h_prev = pp;
158     if (*pp)
159         (*pp)->h_prev = &p->h_next;
160     *pp = p;
161
162     return p;
163 }
164
165 static void move_to_front(Dict_BFile bf, struct Dict_file_block *p)
166 {
167     /* Already at front? */
168     if (!p->lru_next)
169         return ;
170
171     /* Remove */
172     if (p->lru_prev)
173         p->lru_prev->lru_next = p->lru_next;
174     else
175         bf->lru_back = p->lru_next;
176     p->lru_next->lru_prev = p->lru_prev;
177
178     /* Insert at front */
179     p->lru_next = NULL;
180     p->lru_prev = bf->lru_front;
181     if (bf->lru_front)
182         bf->lru_front->lru_next = p;
183     else
184         bf->lru_back = p;
185     bf->lru_front = p;
186 }
187
188 int dict_bf_readp(Dict_BFile bf, int no, void **bufp)
189 {
190     struct Dict_file_block *p;
191     int i;
192     if ((p = find_block(bf, no)))
193     {
194         *bufp = p->data;
195         move_to_front(bf, p);
196         bf->hits++;
197         return 1;
198     }
199     bf->misses++;
200     p = alloc_block(bf, no);
201
202     if (!bf->compact_flag)
203         i = bf_read(bf->bf, no, 0, 0, p->data);
204     else
205     {
206         int effective_block = no / bf->block_size;
207         int effective_offset = no - effective_block * bf->block_size;
208
209         i = bf_read(bf->bf, effective_block, effective_offset,
210                     bf->block_size - effective_offset, p->data);
211         if (i > 0 && effective_offset > 0)
212             i = bf_read(bf->bf, effective_block+1, 0, effective_offset,
213                         (char*) p->data + bf->block_size - effective_offset);
214         i = 1;
215     }
216     if (i > 0)
217     {
218         *bufp = p->data;
219         return i;
220     }
221     release_block(bf, p);
222     *bufp = NULL;
223     return i;
224 }
225
226 int dict_bf_newp(Dict_BFile dbf, int no, void **bufp, int nbytes)
227 {
228     struct Dict_file_block *p;
229     if (!(p = find_block(dbf, no)))
230         p = alloc_block(dbf, no);
231     else
232         move_to_front(dbf, p);
233     *bufp = p->data;
234     memset(p->data, 0, dbf->block_size);
235     p->dirty = 1;
236     p->nbytes = nbytes;
237 #if 0
238     printf("bf_newp of %d:", no);
239     dict_pr_lru(dbf);
240 #endif
241     return 1;
242 }
243
244 int dict_bf_touch(Dict_BFile dbf, int no)
245 {
246     struct Dict_file_block *p;
247     if ((p = find_block(dbf, no)))
248     {
249         p->dirty = 1;
250         return 0;
251     }
252     return -1;
253 }
254
255 /*
256  * Local variables:
257  * c-basic-offset: 4
258  * c-file-style: "Stroustrup"
259  * indent-tabs-mode: nil
260  * End:
261  * vim: shiftwidth=4 tabstop=8 expandtab
262  */
263