file-cache.c revision 8da8fa22f337c7e9f9ec6183e22f351811478387
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* Copyright (c) 2004 Timo Sirainen */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch cache->page_bitmask = buffer_create_dynamic(default_pool, 128);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschvoid file_cache_free(struct file_cache **_cache)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (munmap_anon(cache->mmap_base, cache->mmap_length) < 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschvoid file_cache_set_fd(struct file_cache *cache, int fd)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch file_cache_invalidate(cache, 0, cache->mmap_length);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic int file_cache_set_size(struct file_cache *cache, uoff_t size)
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch i_error("file_cache_set_size(%"PRIuUOFF_T"): size too large",
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* grow mmaping */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_error("mmap_anon(%"PRIuUOFF_T") failed: %m", size);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch new_base = mremap_anon(cache->mmap_base, cache->mmap_length,
7c7117e542b6a44c1db7fc91c0180bdace6dbce7Stephan Bosch i_error("mremap_anon(%"PRIuUOFF_T") failed: %m", size);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenssize_t file_cache_read(struct file_cache *cache, uoff_t offset, size_t size)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch size_t poffset, psize, dest_offset, dest_size;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* make sure our calculations won't overflow. most likely
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch we'll be reading less data, but allow it anyway so caller
dc05b1fb4b7a2b4d91248078311458cb4cbad9a1Stephan Bosch doesn't have to deal with any extra checks. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch offset + size - cache->mmap_length > 1024*1024) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* growing more than a megabyte, make sure that the
201c3b9375760bafbc180629b4c6ad71ed554aecStephan Bosch file is large enough so we don't allocate memory
201c3b9375760bafbc180629b4c6ad71ed554aecStephan Bosch more than needed */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (file_cache_set_size(cache, offset + size) < 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch psize = (offset + size + page_size-1) / page_size - poffset;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch bits = buffer_get_space_unsafe(cache->page_bitmask, 0,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch dest = PTR_OFFSET(cache->mmap_base, dest_offset);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch while (psize > 0) {
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch if (bits[poffset / CHAR_BIT] & (1 << (poffset % CHAR_BIT))) {
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch /* page is already in cache */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* this is the last partially cached block.
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen use the caching only if we don't want to
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen read past read_highwater */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* mark the block noncached again and
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch ret = pread(cache->fd, dest, dest_size, dest_offset);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* EOF. mark the last block as cached even if it
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch isn't completely. read_highwater tells us how far
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch we've actually made. */
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch /* read_highwater needs to be updated. if we didn't
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch just read that block, we can't trust anymore that
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch we have it cached */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* partial read - probably EOF but make sure. */
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch bits[poffset / CHAR_BIT] |= 1 << (poffset % CHAR_BIT);
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschconst void *file_cache_get_map(struct file_cache *cache, size_t *size_r)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschvoid file_cache_write(struct file_cache *cache, const void *data, size_t size,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned char *bits;
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch i_assert(size < (uoff_t)-1 && offset < (uoff_t)-1 - size);
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch if (file_cache_set_size(cache, offset + size) < 0) {
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch /* couldn't grow mapping. just make sure the written memory
38af46387e565053adf6c47f7f6871676d685de8Stephan Bosch area is invalidated then. */
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch memcpy(PTR_OFFSET(cache->mmap_base, offset), data, size);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch unsigned int page = cache->read_highwater / page_size;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch bits = buffer_get_space_unsafe(cache->page_bitmask,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* mark fully written pages cached */
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch bits = buffer_get_space_unsafe(cache->page_bitmask, 0,
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch for (; first_page < last_page; first_page++) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschvoid file_cache_invalidate(struct file_cache *cache, uoff_t offset, uoff_t size)
e4b70fb422bf53ddf017948de26b5ea5a1a262fbStephan Bosch unsigned int i;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if (offset >= cache->read_highwater || size == 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch size = (offset + size + page_size-1) / page_size;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch /* tell operating system that we don't need the memory anymore
833bed942977673526c72e79bccc09314fc57104Phil Carmody and it may free it. don't bother to do it for single pages,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch there's a good chance that they get re-read back
size--;
if (size > 0) {
mask = 0;