1 /* $Id: tradindexed.c 7138 2005-03-16 18:15:51Z hkehoe $
3 ** Interface implementation for the tradindexed overview method.
5 ** This code converts between the internal interface used by the tradindexed
6 ** implementation and the interface expected by the INN overview API. The
7 ** internal interface is in some cases better suited to the data structures
8 ** that the tradindexed overview method uses, and this way the internal
9 ** interface can be kept isolated from the external interface. (There are
10 ** also some operations that can be performed entirely in the interface
17 #include "inn/innconf.h"
18 #include "inn/messages.h"
22 #include "tdx-private.h"
23 #include "tdx-structure.h"
24 #include "tradindexed.h"
26 /* This structure holds all of the data about the open overview files. We can
27 eventually pass one of these structures back to the caller of open when the
28 overview API is more object-oriented. */
30 struct group_index *index;
35 /* Global data about the open tradindexed method. */
36 static struct tradindexed *tradindexed;
40 ** Helper function to open a group_data structure via the cache, inserting it
41 ** into the cache if it wasn't found in the cache.
43 static struct group_data *
44 data_cache_open(struct tradindexed *global, const char *group,
45 struct group_entry *entry)
47 struct group_data *data;
49 data = tdx_cache_lookup(global->cache, entry->hash);
51 data = tdx_data_open(global->index, group, entry);
54 tdx_cache_insert(global->cache, entry->hash, data);
61 ** Helper function to reopen the data files and remove the old entry from the
62 ** cache if we think that might help better fulfill a search.
64 static struct group_data *
65 data_cache_reopen(struct tradindexed *global, const char *group,
66 struct group_entry *entry)
68 struct group_data *data;
70 tdx_cache_delete(global->cache, entry->hash);
71 data = tdx_data_open(global->index, group, entry);
74 tdx_cache_insert(global->cache, entry->hash, data);
80 ** Open the overview method.
83 tradindexed_open(int mode)
85 unsigned int cache_size, fdlimit;
87 if (tradindexed != NULL) {
88 warn("tradindexed: overview method already open");
91 tradindexed = xmalloc(sizeof(struct tradindexed));
92 tradindexed->index = tdx_index_open((mode & OV_WRITE) ? true : false);
93 tradindexed->cutoff = false;
95 /* Use a cache size of two for read-only connections. We may want to
96 rethink the limitation of the cache for reading later based on
97 real-world experience. */
98 cache_size = (mode & OV_WRITE) ? innconf->overcachesize : 1;
99 fdlimit = getfdlimit();
100 if (fdlimit > 0 && fdlimit < cache_size * 2) {
101 warn("tradindexed: not enough file descriptors for an overview cache"
102 " size of %u; increase rlimitnofile or decrease overcachesize"
103 " to at most %u", cache_size, fdlimit / 2);
104 cache_size = (fdlimit > 2) ? fdlimit / 2 : 1;
106 tradindexed->cache = tdx_cache_create(cache_size);
108 return (tradindexed->index == NULL) ? false : true;
113 ** Get statistics about a group. Convert between the multiple pointer API
114 ** and the structure API used internally.
117 tradindexed_groupstats(char *group, int *low, int *high, int *count,
120 const struct group_entry *entry;
122 if (tradindexed == NULL || tradindexed->index == NULL) {
123 warn("tradindexed: overview method not initialized");
126 entry = tdx_index_entry(tradindexed->index, group);
134 *count = entry->count;
142 ** Add a new newsgroup to the index.
145 tradindexed_groupadd(char *group, ARTNUM low, ARTNUM high, char *flag)
147 if (tradindexed == NULL || tradindexed->index == NULL) {
148 warn("tradindexed: overview method not initialized");
151 return tdx_index_add(tradindexed->index, group, low, high, flag);
156 ** Delete a newsgroup from the index.
159 tradindexed_groupdel(char *group)
161 if (tradindexed == NULL || tradindexed->index == NULL) {
162 warn("tradindexed: overview method not initialized");
165 return tdx_index_delete(tradindexed->index, group);
170 ** Add data about a single article. Convert between the multiple argument
171 ** API and the structure API used internally, and also implement low article
172 ** cutoff if that was requested.
175 tradindexed_add(char *group, ARTNUM artnum, TOKEN token, char *data,
176 int length, time_t arrived, time_t expires)
178 struct article article;
179 struct group_data *group_data;
180 struct group_entry *entry;
182 if (tradindexed == NULL || tradindexed->index == NULL) {
183 warn("tradindexed: overview method not initialized");
187 /* Get the group index entry and don't do any work if cutoff is set and
188 the article number is lower than the low water mark for the group. */
189 entry = tdx_index_entry(tradindexed->index, group);
192 if (tradindexed->cutoff && entry->low > artnum)
195 /* Fill out the article data structure. */
196 article.number = artnum;
197 article.overview = data;
198 article.overlen = length;
199 article.token = token;
200 article.arrived = arrived;
201 article.expires = expires;
203 /* Open the appropriate data structures, using the cache. */
204 group_data = data_cache_open(tradindexed, group, entry);
205 if (group_data == NULL)
207 return tdx_data_add(tradindexed->index, entry, group_data, &article);
212 ** Cancel an article. At present, tradindexed can't do anything with this
213 ** information because we lack a mapping from the token to newsgroup names
214 ** and article numbers, so we just silently return true and let expiration
215 ** take care of this.
218 tradindexed_cancel(TOKEN token UNUSED)
225 ** Open an overview search. Open the appropriate group and then start a
229 tradindexed_opensearch(char *group, int low, int high)
231 struct group_entry *entry;
232 struct group_data *data;
234 if (tradindexed == NULL || tradindexed->index == NULL) {
235 warn("tradindexed: overview method not initialized");
238 entry = tdx_index_entry(tradindexed->index, group);
241 data = data_cache_open(tradindexed, group, entry);
244 if (entry->base != data->base)
245 if (data->base > (ARTNUM) low && entry->base < data->base) {
246 data = data_cache_reopen(tradindexed, group, entry);
250 return tdx_search_open(data, low, high, entry->high);
255 ** Get the next article returned by a search. Convert between the multiple
256 ** pointer API and the structure API we use internally.
259 tradindexed_search(void *handle, ARTNUM *artnum, char **data, int *length,
260 TOKEN *token, time_t *arrived)
262 struct article article;
264 if (tradindexed == NULL || tradindexed->index == NULL) {
265 warn("tradindexed: overview method not initialized");
268 if (!tdx_search(handle, &article))
271 *artnum = article.number;
273 *data = (char *) article.overview;
275 *length = article.overlen;
277 *token = article.token;
279 *arrived = article.arrived;
285 ** Close an overview search.
288 tradindexed_closesearch(void *handle)
290 tdx_search_close(handle);
295 ** Get information for a single article. Open the appropriate group and then
296 ** convert from the pointer API to the struct API used internally.
299 tradindexed_getartinfo(char *group, ARTNUM artnum, TOKEN *token)
301 struct group_entry *entry;
302 struct group_data *data;
303 const struct index_entry *index_entry;
305 if (tradindexed == NULL || tradindexed->index == NULL) {
306 warn("tradindexed: overview method not initialized");
309 entry = tdx_index_entry(tradindexed->index, group);
312 data = data_cache_open(tradindexed, group, entry);
315 if (entry->base != data->base)
316 if (data->base > artnum && entry->base <= artnum) {
317 data = data_cache_reopen(tradindexed, group, entry);
321 index_entry = tdx_article_entry(data, artnum, entry->high);
322 if (index_entry == NULL)
325 *token = index_entry->token;
331 ** Expire a single newsgroup.
334 tradindexed_expiregroup(char *group, int *low, struct history *history)
339 /* tradindexed doesn't have any periodic cleanup. */
343 status = tdx_expire(group, &new_low, history);
344 if (status && low != NULL)
345 *low = (int) new_low;
351 ** Set various options or query various paramaters for the overview method.
352 ** The interface is, at present, not particularly sane.
355 tradindexed_ctl(OVCTLTYPE type, void *val)
361 if (tradindexed == NULL) {
362 warn("tradindexed: overview method not initialized");
372 sort = (OVSORTTYPE *) val;
377 tradindexed->cutoff = *b;
395 ** Close the overview method.
398 tradindexed_close(void)
400 if (tradindexed != NULL) {
401 if (tradindexed->index != NULL)
402 tdx_index_close(tradindexed->index);
403 if (tradindexed->cache != NULL)
404 tdx_cache_free(tradindexed->cache);