8350c3e69a4729f0bdcd0d90a8dcd228d17c86a8
[idzebra-moved-to-github.git] / dict / drdwr.c
1 /* $Id: drdwr.c,v 1.14 2004-11-19 10:26:55 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #ifndef WIN32
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.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