Use new version of bf_read, bf_write.
[idzebra-moved-to-github.git] / dict / drdwr.c
1 #include <sys/types.h>
2 #include <fcntl.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <assert.h>
8
9 #include <dict.h>
10
11 static void pr_lru (Dict_BFile bf)
12 {
13     struct Dict_file_block *p;
14     for (p=bf->lru_back; p; p = p->lru_next)
15     {
16         printf (" %d", p->no);
17     }
18     printf ("\n");
19     fflush (stdout);
20 }
21
22 static struct Dict_file_block *find_block (Dict_BFile bf, int no)
23 {
24     struct Dict_file_block *p;
25
26     for (p=bf->hash_array[no% bf->hash_size]; p; p=p->h_next)
27         if (p->no == no)
28             break;
29     return p;
30 }
31
32 static void release_block (Dict_BFile bf, struct Dict_file_block *p)
33 {
34     assert (p);
35
36     /* remove from lru queue */    
37     if (p->lru_prev)
38         p->lru_prev->lru_next = p->lru_next;
39     else
40         bf->lru_back = p->lru_next;
41     if (p->lru_next)
42         p->lru_next->lru_prev = p->lru_prev;
43     else
44         bf->lru_back = p->lru_prev;
45
46     /* remove from hash chain */
47     *p->h_prev = p->h_next;
48     if (p->h_next)
49         p->h_next->h_prev = p->h_prev;
50
51     /* move to list of free blocks */
52     p->h_next = bf->free_list;
53     bf->free_list = p;
54 }
55
56 void dict_bf_flush_blocks (Dict_BFile bf, int no_to_flush)
57 {
58     struct Dict_file_block *p;
59     int i;
60     for (i=0; i != no_to_flush && bf->lru_back; i++)
61     {
62         p = bf->lru_back;
63         if (p->dirty)
64             bf_write (bf->bf, p->no, 0, 0, p->data);
65         release_block (bf, p);
66     }
67 }
68
69 static struct Dict_file_block *alloc_block (Dict_BFile bf, int no)
70 {
71     struct Dict_file_block *p, **pp;
72
73     if (!bf->free_list)
74         dict_bf_flush_blocks (bf, 1);
75     assert (bf->free_list);
76     p = bf->free_list;
77     bf->free_list = p->h_next;
78     p->dirty = 0;
79     p->no = no;
80
81     /* insert at front in lru chain */
82     p->lru_next = NULL;
83     p->lru_prev = bf->lru_front;
84     if (bf->lru_front)
85         bf->lru_front->lru_next = p;
86     else
87         bf->lru_back = p;
88     bf->lru_front = p;
89
90     /* insert in hash chain */
91     pp = bf->hash_array + (no % bf->hash_size);
92     p->h_next = *pp;
93     p->h_prev = pp;
94     if (*pp)
95         (*pp)->h_prev = &p->h_next;
96     *pp = p;
97    
98     return p;
99 }
100
101 static void move_to_front (Dict_BFile bf, struct Dict_file_block *p)
102 {
103     /* Already at front? */
104     if (!p->lru_next)
105         return ;   
106
107     /* Remove */
108     if (p->lru_prev)
109         p->lru_prev->lru_next = p->lru_next;
110     else
111         bf->lru_back = p->lru_next;
112     p->lru_next->lru_prev = p->lru_prev;
113
114     /* Insert at front */
115     p->lru_next = NULL;
116     p->lru_prev = bf->lru_front;
117     if (bf->lru_front)
118         bf->lru_front->lru_next = p;
119     else
120         bf->lru_back = p;
121     bf->lru_front = p;
122 }
123
124 int bf_readp (Dict_BFile bf, int no, void **bufp)
125 {
126     struct Dict_file_block *p;
127     int i;
128     if ((p = find_block (bf, no)))
129     {
130         *bufp = p->data;
131         move_to_front (bf, p);
132         bf->hits++;
133         return 1;
134     }
135     bf->misses++;
136     p = alloc_block (bf, no);
137     i = bf_read (bf->bf, no, 0, 0, p->data);
138     if (i > 0)
139     {
140         *bufp = p->data;
141         return i;
142     }
143     release_block (bf, p);
144     *bufp = NULL;
145     return i;
146 }
147
148 int bf_newp (Dict_BFile bf, int no, void **bufp)
149 {
150     struct Dict_file_block *p;
151     if (!(p = find_block (bf, no)))
152         p = alloc_block (bf, no);
153     else
154         move_to_front (bf, p);
155     *bufp = p->data;
156     memset (p->data, 0, bf->bf->block_size);
157     p->dirty = 1;
158 #if 0
159     printf ("bf_newp of %d:", no);
160     pr_lru (bf);
161 #endif
162     return 1;
163 }
164
165 int bf_touch (Dict_BFile bf, int no)
166 {
167     struct Dict_file_block *p;
168     if ((p = find_block (bf, no)))
169     {
170         p->dirty = 1;
171         return 0;
172     }
173     return -1;
174 }
175