Annotation of src/usr.bin/cvs/cache.c, Revision 1.1.1.1
1.1 jfb 1: /* $OpenBSD$ */
2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/param.h>
28: #include <sys/queue.h>
29: #include <sys/time.h>
30:
31: #include <stdlib.h>
32: #include <stdio.h>
33: #include <unistd.h>
34: #include <errno.h>
35: #include <string.h>
36:
37: #include "log.h"
38: #include "rcs.h"
39: #include "cache.h"
40:
41: #define RCS_CACHE_BUCKETS 256
42:
43:
44: struct rcs_cachent {
45: u_int rc_hits;
46: u_int8_t rc_hash;
47: RCSFILE *rc_rfp;
48: struct timeval rc_atime;
49:
50: TAILQ_ENTRY(rcs_cachent) rc_list;
51: TAILQ_ENTRY(rcs_cachent) rc_lru;
52: };
53:
54:
55: static u_int8_t rcs_cache_hash (const char *);
56:
57:
58: TAILQ_HEAD(rcs_cachebkt, rcs_cachent) rcs_cache[RCS_CACHE_BUCKETS];
59:
60: TAILQ_HEAD(rcs_lruhead, rcs_cachent) rcs_cache_lru;
61:
62: u_int rcs_cache_maxent;
63: u_int rcs_cache_nbent;
64:
65:
66:
67: /*
68: * rcs_cache_init()
69: *
70: * Initialize the RCS file data cache.
71: * Returns 0 on success, -1 on failure.
72: */
73:
74: int
75: rcs_cache_init(u_int maxent)
76: {
77: u_int i;
78:
79: for (i = 0; i < RCS_CACHE_BUCKETS; i++)
80: TAILQ_INIT(&rcs_cache[i]);
81:
82: TAILQ_INIT(&rcs_cache_lru);
83:
84: rcs_cache_maxent = maxent;
85: rcs_cache_nbent = 0;
86:
87: return (0);
88: }
89:
90:
91: /*
92: * rcs_cache_destroy()
93: */
94:
95: void
96: rcs_cache_destroy(void)
97: {
98: }
99:
100:
101: /*
102: * rcs_cache_fetch()
103: *
104: */
105:
106: RCSFILE*
107: rcs_cache_fetch(const char *path)
108: {
109: u_int8_t hash;
110: struct rcs_cachent *rcp;
111: RCSFILE *rfp;
112:
113: rfp = NULL;
114: hash = rcs_cache_hash(path);
115:
116: TAILQ_FOREACH(rcp, &(rcs_cache[hash]), rc_list) {
117: if (strcmp(path, rcp->rc_rfp->rf_path) == 0) {
118: rfp = rcp->rc_rfp;
119: break;
120: }
121: }
122:
123: if (rcp != NULL) {
124: (void)gettimeofday(&(rcp->rc_atime), NULL);
125: rcp->rc_hits++;
126:
127: /* move this item back at the end of the LRU */
128: TAILQ_REMOVE(&rcs_cache_lru, rcp, rc_lru);
129: TAILQ_INSERT_TAIL(&rcs_cache_lru, rcp, rc_lru);
130:
131: /* increment reference count for caller */
132: rfp->rf_ref++;
133: }
134:
135: return (rfp);
136: }
137:
138:
139: /*
140: * rcs_cache_store()
141: *
142: * Store the RCSFILE <rfp> in the RCS file cache. By storing the file, its
143: * reference count gets incremented for the cache reference, so the caller
144: * should still rcs_close() the file once they are done with it.
145: * Returns 0 on success, or -1 on failure.
146: */
147:
148: int
149: rcs_cache_store(RCSFILE *rfp)
150: {
151: struct rcs_cachent *rcp, *old_rcp;
152:
153: /* don't store the same element twice */
154: if (rcs_cache_fetch(rfp->rf_path) != NULL)
155: return (0);
156:
157: rcp = (struct rcs_cachent *)malloc(sizeof(*rcp));
158: if (rcp == NULL) {
159: cvs_log(LP_ERRNO, "failed to allocate RCS cache entry");
160: return (-1);
161: }
162:
163: rcp->rc_hits = 0;
164:
165: rcp->rc_rfp = rfp;
166: rfp->rf_ref++;
167:
168: rcp->rc_hash = rcs_cache_hash(rfp->rf_path);
169:
170: rcs_cache_nbent++;
171: if (rcs_cache_nbent == rcs_cache_maxent) {
172: /* ditch the oldest entry in the LRU */
173: old_rcp = TAILQ_FIRST(&rcs_cache_lru);
174: TAILQ_REMOVE(&rcs_cache_lru, old_rcp, rc_lru);
175: TAILQ_REMOVE(&(rcs_cache[old_rcp->rc_hash]), old_rcp, rc_list);
176:
177: /* free our reference */
178: rcs_close(old_rcp->rc_rfp);
179: free(old_rcp);
180: }
181:
182: TAILQ_INSERT_TAIL(&(rcs_cache[rcp->rc_hash]), rcp, rc_list);
183: TAILQ_INSERT_TAIL(&rcs_cache_lru, rcp, rc_lru);
184:
185: return (0);
186: }
187:
188:
189: /*
190: * rcs_cache_hash()
191: *
192: * Hash the <path> string.
193: */
194:
195: static u_int8_t
196: rcs_cache_hash(const char *path)
197: {
198: const char *sp;
199: u_int8_t hash;
200:
201: hash = 0;
202: for (sp = path; *sp != '\0'; sp++)
203: hash ^= (*sp << 3) ^ (*sp >> 2);
204:
205: return (hash);
206: }