xref: /dragonfly/sbin/hammer/cache.c (revision 6ab64ab6)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sbin/hammer/cache.c,v 1.5 2008/05/16 18:39:03 dillon Exp $
35  */
36 
37 #include "hammer_util.h"
38 
39 static int CacheUse;
40 static int CacheMax = 16 * 1024 * 1024;
41 static int NCache;
42 static TAILQ_HEAD(, cache_info) CacheList = TAILQ_HEAD_INITIALIZER(CacheList);
43 
44 int
45 hammer_parse_cache_size(const char *arg)
46 {
47 	char *ptr;
48 	int size = strtol(arg, &ptr, 0);
49 
50 	switch(*ptr) {
51 	case 'm':
52 	case 'M':
53 		size *= 1024;
54 		/* fall through */
55 	case 'k':
56 	case 'K':
57 		size *= 1024;
58 		++ptr;
59 		break;
60 	case '\0':
61 	case ':':
62 		/* bytes if no suffix */
63 		break;
64 	default:
65 		return(-1);
66 	}
67 
68 	if (*ptr == ':') {
69 		UseReadAhead = strtol(ptr + 1, NULL, 0);
70 		UseReadBehind = -UseReadAhead;
71 	}
72 	if (size < 1024 * 1024)
73 		size = 1024 * 1024;
74 	if (UseReadAhead < 0)
75 		return(-1);
76 	if (UseReadAhead * HAMMER_BUFSIZE / size / 16) {
77 		UseReadAhead = size / 16 / HAMMER_BUFSIZE;
78 		UseReadBehind = -UseReadAhead;
79 	}
80 
81 	CacheMax = size;
82 	return(0);
83 }
84 
85 void
86 hammer_cache_add(struct cache_info *cache)
87 {
88 	TAILQ_INSERT_HEAD(&CacheList, cache, entry);
89 	CacheUse += HAMMER_BUFSIZE;
90 	++NCache;
91 }
92 
93 void
94 hammer_cache_del(struct cache_info *cache)
95 {
96 	TAILQ_REMOVE(&CacheList, cache, entry);
97 	CacheUse -= HAMMER_BUFSIZE;
98 	--NCache;
99 }
100 
101 void
102 hammer_cache_used(struct cache_info *cache)
103 {
104 	TAILQ_REMOVE(&CacheList, cache, entry);
105 	TAILQ_INSERT_TAIL(&CacheList, cache, entry);
106 }
107 
108 void
109 hammer_cache_flush(void)
110 {
111 	struct cache_info *cache;
112 	struct cache_info *p = NULL;
113 	int target;
114 	int count = 0;
115 
116 	if (CacheUse >= CacheMax) {
117 		target = CacheMax / 2;
118 		while ((cache = TAILQ_FIRST(&CacheList)) != NULL) {
119 			if (cache == p)
120 				break;  /* seen this before */
121 			++count;
122 			if (cache->refs) {
123 				if (p == NULL)
124 					p = cache;
125 				hammer_cache_used(cache);
126 				continue;
127 			}
128 			if (count >= NCache) {
129 				CacheMax += 8 * 1024 * 1024;
130 				target = CacheMax / 2;
131 				count = 1;
132 			}
133 			cache->refs = 1;
134 			cache->delete = 1;
135 			--count;
136 			rel_buffer((struct buffer_info*)cache);
137 
138 			if (CacheUse < target)
139 				break;
140 		}
141 	}
142 }
143 
144