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