003fd21bc0b8fa8713f00e009c88bac7cbb82f83
[dragonfly.git] / sbin / hammer / cache.c
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 = HAMMER_BUFSIZE * 1024;
41 static TAILQ_HEAD(, cache_info) CacheList = TAILQ_HEAD_INITIALIZER(CacheList);
42
43 int
44 hammer_parse_cache_size(const char *arg)
45 {
46         char *ptr;
47         int size = strtol(arg, &ptr, 0);
48
49         switch(*ptr) {
50         case 'm':
51         case 'M':
52                 size *= 1024;
53                 /* fall through */
54         case 'k':
55         case 'K':
56                 size *= 1024;
57                 ++ptr;
58                 break;
59         case '\0':
60         case ':':
61                 /* bytes if no suffix */
62                 break;
63         default:
64                 return(-1);
65         }
66
67         if (*ptr == ':') {
68                 UseReadAhead = strtol(ptr + 1, NULL, 0);
69                 UseReadBehind = -UseReadAhead;
70         }
71         if (size < 1024 * 1024)
72                 size = 1024 * 1024;
73         if (UseReadAhead < 0)
74                 return(-1);
75         if (UseReadAhead * HAMMER_BUFSIZE / size / 16) {
76                 UseReadAhead = size / 16 / HAMMER_BUFSIZE;
77                 UseReadBehind = -UseReadAhead;
78         }
79
80         CacheMax = size;
81         return(0);
82 }
83
84 void
85 hammer_cache_add(struct cache_info *cache)
86 {
87         TAILQ_INSERT_HEAD(&CacheList, cache, entry);
88         CacheUse += HAMMER_BUFSIZE;
89 }
90
91 void
92 hammer_cache_del(struct cache_info *cache)
93 {
94         TAILQ_REMOVE(&CacheList, cache, entry);
95         CacheUse -= HAMMER_BUFSIZE;
96 }
97
98 void
99 hammer_cache_used(struct cache_info *cache)
100 {
101         TAILQ_REMOVE(&CacheList, cache, entry);
102         TAILQ_INSERT_TAIL(&CacheList, cache, entry);
103 }
104
105 void
106 hammer_cache_flush(void)
107 {
108         struct cache_info *cache;
109         struct cache_info *first = NULL;
110         int count = 0;
111
112         if (CacheUse >= CacheMax) {
113                 while ((cache = TAILQ_FIRST(&CacheList)) != NULL) {
114                         if (cache == first)
115                                 break; /* seen this ref'd before */
116
117                         if (cache->refs) {
118                                 if (first == NULL)
119                                         first = cache;
120                                 hammer_cache_used(cache);
121                                 count++;
122                                 continue;
123                         }
124                         if (count >= (CacheUse / HAMMER_BUFSIZE)) {
125                                 CacheMax += HAMMER_BUFSIZE * 512;
126                                 count = 0;
127                         }
128
129                         cache->refs = 1;
130                         cache->delete = 1;
131                         rel_buffer((struct buffer_info*)cache);
132
133                         if (CacheUse < CacheMax / 2)
134                                 break;
135                 }
136         }
137 }
138