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