📄 cache.c
字号:
/* * Copyright (c) 1998-2001 Caucho Technology -- all rights reserved * * Caucho Technology permits redistribution, modification and use * of this file in source and binary form ("the Software") under the * Caucho Developer Source License ("the License"). The following * conditions must be met: * * 1. Each copy or derived work of the Software must preserve the copyright * notice and this notice unmodified. * * 2. Redistributions of the Software in source or binary form must include * an unmodified copy of the License, normally in a plain ASCII text * * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and * may not be used to endorse products derived from this software. * "Resin" or "Caucho" may not appear in the names of products derived * from this software. * * 4. Caucho Technology requests that attribution be given to Resin * in any manner possible. We suggest using the "Resin Powered" * button or creating a "powered by Resin(tm)" link to * http://www.caucho.com for each page served by Resin. * * This Software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES. * * @author Scott Ferguson */#include <linux/kernel.h>#include <linux/proc_fs.h>#include <linux/ctype.h>#include <linux/fs.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <net/ip.h>#include "hardcore.h"typedef struct entry_t { char buf[256]; char *url; int use_count; int expires; struct file *file; int length; char is_live; char is_dead;} entry_t;#define CACHE_SIZE 128static int g_count;static struct entry_t g_cache[CACHE_SIZE];static struct dentry *lookup_create(struct nameidata *nd, int is_dir){ struct dentry *dentry; down(&nd->dentry->d_inode->i_sem); dentry = ERR_PTR(-EEXIST); if (nd->last_type != LAST_NORM) goto fail; dentry = lookup_hash(&nd->last, nd->dentry); if (IS_ERR(dentry)) goto fail; if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) goto enoent; return dentry;enoent: dput(dentry); dentry = ERR_PTR(-ENOENT);fail: return dentry;}intcache_mkdir(const char *pathname, int mode){ int error = 0; struct dentry *dir; struct nameidata nd; lock_kernel(); if (path_init(pathname, LOOKUP_PARENT, &nd)) error = path_walk(pathname, &nd); if (error) goto out; dir = lookup_create(&nd, 1); error = PTR_ERR(dir); if (!IS_ERR(dir)) { error = vfs_mkdir(nd.dentry->d_inode, dir, mode); dput(dir); } up(&nd.dentry->d_inode->i_sem); path_release(&nd);out: unlock_kernel(); return error;}/** * Callback from the readdir routine for removing all the files in the * cache directory. * * @param vdir our parameter storing the directory file struct * @param name the name of the listed file * @param namlen the length of the name * @param offset ?? * @param ino inode of the file */static intremove_file(void *vdir, const char *name, int namlen, off_t offset, ino_t ino){ struct file *dir = (struct file *) vdir; struct dentry *file; struct inode *inode = dir->f_dentry->d_inode; struct qstr qstr; if (name[0] == '.') return 0; qstr.name = name; qstr.len = namlen; qstr.hash = full_name_hash(name, namlen); LOG(("remove %s\n", name)); file = d_lookup(dir->f_dentry, &qstr); if (file && inode) vfs_unlink(inode, file); if (file) dput(file); return 0;}static entry_t *cache_get(char *url){ int hash = 37; int ch; int i; for (i = 0; (ch = url[i]); i++) hash = 65521 * hash + ch * 29; hash &= 0x7fffffff; for (i = 5; i > 0; i--) { hash %= CACHE_SIZE; if (! g_cache[hash].url) return &g_cache[hash]; else if (! strcmp(g_cache[hash].url, url)) return &g_cache[hash]; hash++; } return 0;}/** * Remove a cache entry */static voidcache_remove(entry_t *cache){ LOG(("cache remove %s\n", cache->url)); cache->is_live = 0; cache->url = 0; /* * Don't remove because we'll reuse it. cache->file = 0; if (file) { // XXX: unlink, too filp_close(file, current->files); } */}/** * Remove a cache entry */static voidcache_truncate(entry_t *cache){ struct file *file = cache->file; struct inode *inode = file->f_dentry->d_inode; LOG(("cache truncate %s %p\n", cache->url ? cache->url : "null", inode)); cache->is_live = 0; cache->url = 0; if (inode) inode->i_op->truncate(inode); LOG(("post truncate\n"));}intcache_start(browser_t *browser){ char buf[256]; struct file *file = 0; struct nameidata nd; int flag; int err; entry_t *cache = cache_get(browser->url); LOG(("cache start %s %p\n", browser->url, cache)); // If already have an entry, don't cache // XXX: really need to do an LRU here if (! cache) return 0; else if (! cache->url && cache->file) { // Truncate and return the cache cache_truncate(cache); cache->file->f_pos = 0; cache->is_live = 0; cache->url = cache->buf; strcpy(cache->url, browser->url); browser->cache = cache; cache->length = 0; return 1; } else if (! cache->url) { } else if (cache->expires < browser->now) { // Truncate and return the cache cache_truncate(cache); cache->file->f_pos = 0; cache->is_live = 0; cache->url = cache->buf; strcpy(cache->url, browser->url); browser->cache = cache; cache->length = 0; return 1; } else return 0; sprintf(buf, "/usr/tmp/caucho/cache/t%d.tmp", g_count++); flag = O_CREAT|0x3; // err = open_namei(buf, flag, 0664, &nd); err = -1; if (err < 0) { LOG(("can't open 0\n")); return 0; } file = dentry_open(nd.dentry, nd.mnt, flag); if (! file) { LOG(("can't open\n")); return 0; } cache->is_live = 0; cache->url = cache->buf; strcpy(cache->url, browser->url); browser->cache = cache; cache->file = file; cache->length = 0; LOG(("caching %s!\n", cache->url)); return 1;}/** * Writes data to the cache. */voidcache_write(browser_t *browser, char *data, int len){ mm_segment_t oldfs; int write_len; struct file *file = browser->cache->file; LOG(("writing\n")); oldfs = get_fs(); set_fs(KERNEL_DS); write_len = file->f_op->write(file, data, len, &file->f_pos); set_fs(oldfs); LOG(("write %d -> %d\n", len, write_len));}/** * Kill the caching on this file because of some error during * the request. */voidcache_kill(browser_t *browser){ entry_t *cache = browser->cache; struct file *file = cache->file; LOG(("kill %s\n", browser->url)); cache->file = 0; cache->url = 0; cache->is_live = 0; browser->cache = 0; filp_close(file, current->files); // XXX: needs unlink too}/** * Finish loading of a cache. */voidcache_finish(browser_t *browser){ entry_t *cache = browser->cache; struct file *file; if (! cache) return; browser->cache = 0; file = cache->file; cache->length = file->f_pos; cache->expires = browser->expires; cache->is_live = 1; LOG(("finished %s %p %d %p\n", cache->url, file, cache->length, browser));}/** * Writes a string to the buffer. */static intcse_write(char *buf, int off, char *str){ while (*str) buf[off++] = *str++; return off;}intcache_lookup(browser_t *browser){ entry_t *cache = cache_get(browser->url); if (! cache) { LOG(("no cache lookup %s\n", browser->url)); return 0; } else if (! cache->is_live) { LOG(("not live %s %x\n", browser->url, cache->url)); return 0; } else if (browser->now < cache->expires) { int len = 0; char *buf = browser->cout_buf; LOG(("cache lookup %s\n", browser->url)); browser->cache = cache; browser->state = RHC_CACHE_WRITE; browser->cache_offset = 0; len = cse_write(buf, len, "HTTP/1.0 200 OK\r\n"); len = cse_write(buf, len, "Connection: close\r\n"); len = cse_write(buf, len, "Server: ResinHardCore/1.3\r\n"); len += sprintf(buf + len, "Content-Length: %d\r\nDate: ", cache->length); len += format_now(buf + len); len = cse_write(buf, len, "\r\n\r\n"); browser->cout_length = len; cache->use_count++; if (cache_read(browser)) browser_wake(browser); return 1; } else { cache_remove(cache); return 0; }}intcache_read(browser_t *browser){ entry_t *cache = browser->cache; struct file *file = cache->file; int len; mm_segment_t oldfs; loff_t offset = browser->cache_offset; char *buf; oldfs = get_fs(); set_fs(KERNEL_DS); buf = browser->cout_buf + browser->cout_length; len = 4096 - browser->cout_length; if (len > cache->length - browser->cache_offset) len = cache->length - browser->cache_offset; len = file->f_op->read(file, buf, len, &offset); set_fs(oldfs); if (len > 0) { LOG(("cache read %d live %d\n", len, cache->is_live)); browser->cache_offset += len; if (browser->cache_offset >= cache->length) { browser->write_state = RHC_BROWSER_QUIT; browser->cache = 0; } else browser->write_state = browser->state; browser->state = RHC_BROWSER_WRITE; browser->iov[0].iov_base = browser->cout_buf; browser->iov[0].iov_len = browser->cout_length + len; browser->iov_index = 1; browser->cout_length = 0; return browser_write_iov(browser) > 0; } else { // done? LOG(("browser done len:%d live:%d?\n", len, cache->is_live)); browser->cache = 0; browser->state = RHC_BROWSER_QUIT; return 1; }}static voidcache_clear(){ struct file *dir = filp_open("/usr/tmp/caucho/cache", O_RDONLY, 0777); int error; if (! dir) return; down(&dir->f_dentry->d_inode->i_sem); error = dir->f_op->readdir(dir, dir, remove_file); up(&dir->f_dentry->d_inode->i_sem); filp_close(dir, current->files);}intcache_init(){ LOG(("cache init\n")); lock_kernel(); cache_mkdir("/usr/tmp/caucho", 0777); cache_mkdir("/usr/tmp/caucho/cache", 0777); cache_clear(); unlock_kernel(); return 1;}/** * Cleanup the cache module on module shutdown. */voidcache_cleanup(){ int i; for (i = 0; i < CACHE_SIZE; i++) { entry_t *cache = &g_cache[i]; struct file *file = cache->file; // XXX: unlink? if (file) filp_close(file, current->files); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -