From cce3a8f91fab4c80fa6041b0bba202ad71c2ff9c Mon Sep 17 00:00:00 2001 From: carlosm Date: Tue, 28 Jun 2005 23:13:47 +0000 Subject: [PATCH] Modified Files: client/Buffercache.cc client/Buffercache.h Support for implementation of inode_flush and flush. UNTESTED git-svn-id: https://ceph.svn.sf.net/svnroot/ceph@360 29311d96-e01e-0410-9327-a35deaab8ce9 --- ceph/client/Buffercache.cc | 35 +++++++++------- ceph/client/Buffercache.h | 84 ++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/ceph/client/Buffercache.cc b/ceph/client/Buffercache.cc index 21386874b94..ed6572add66 100644 --- a/ceph/client/Buffercache.cc +++ b/ceph/client/Buffercache.cc @@ -46,12 +46,10 @@ void Filecache::map_existing(size_t len, if (next_off < off + len) { holes[next_off] = (size_t) (off + len - next_off); } - // FIXME: consolidate holes } -list Filecache::simplify() +void Filecache::simplify(list& removed) { - list removed; map::iterator start, next; start = buffer_map.begin(); while (start != buffer_map.end()) { @@ -61,7 +59,7 @@ list Filecache::simplify() (*start)->second->state == (*next)->second->state && (*start)->second->offset + (*start)->second->len == (*next)->second->offset) { (*start)->second->claim_append((*next)->second); - buffer_map.erase((*next)->first); + buffer_map.erase((*next)->first); (*next)->second->put(); removed.push_back((*next)->second); next++; } else { @@ -70,7 +68,6 @@ list Filecache::simplify() } start = next; } - return removed; } void Filecache::copy_out(size_t size, off_t offset, char *dst) @@ -111,8 +108,8 @@ void Buffercache::insert(Bufferhead *bh) { bcache_map[bh->ino] = fc; } if (fc->buffermap.count(bh->offset)) assert(0); // fail loudly if offset already exists! - fc->buffer_map[bh->offset] = bh; - lru.lru_insert_top(bh); + fc->buffer_map[bh->offset] = bh; bh->get(); + lru.lru_insert_top(bh); bh->get(); clean_size += bh->len; } @@ -165,12 +162,20 @@ size_t Buffercache::touch_continuous(map& hits, size_t size, void Buffercache::simplify(inodeno_t ino) { Filecache *fc = bcache_map[ino]; - list removed = fc->simplify(); + list removed; + fc->simplify(&removed); for (list::iterator it = removed.begin(); it != removed.end(); it++) { - lru.lru_remove(*it); - delete *it; + lru.lru_remove(*it); (*it)->put(); + if (dirty_buffers.count(*it)) { + dirty_buffers.erase(*it); + (*it)->put(); + } + if (bcache_map[ino]->dirty_buffers.count(*it)) { + bcache_map[ino]->dirty_buffers.erase(*it) + (*it)->put(); + } } } @@ -191,8 +196,8 @@ Bufferhead *Buffercache::alloc_buffers(ino, offset, size) void Buffercache::map_or_alloc(inodeno_t ino, size_t len, off_t off, - map *buffers, - map *inflight) + map& buffers, + map& inflight) { Filecache *fc = bcache_map[ino]; map holes; @@ -214,10 +219,10 @@ void Buffercache::free_buffers(Bufferhead *bh) { assert(bh->state == BUFH_STATE_CLEAN); assert(bh->lru_is_expirable()); - bcache_map[bh->ino]->buffer_map.erase(bh->offset); - lru.lru_remove(bh); clean_size -= bh->len; - delete bh; + lru.lru_remove(bh); bh->put(); + assert(bh->ref == 1); // next put is going to delete it + bcache_map[bh->ino]->buffer_map.erase(bh->offset); bh->put(); } void Buffercache::release_file(inodeno_t ino) diff --git a/ceph/client/Buffercache.h b/ceph/client/Buffercache.h index fa30708a822..5988adf28b4 100644 --- a/ceph/client/Buffercache.h +++ b/ceph/client/Buffercache.h @@ -16,17 +16,6 @@ class Buffercache; class Bufferhead : public LRUObject { - // reference counter - int ref; - void get() { - if (ref == 0) lru_pin(); - ++ref; - } - void put() { - --ref; - if (ref == 0) lru_unpin(); - } - public: // FIXME: make more private and write some accessors off_t offset; size_t len; @@ -38,10 +27,10 @@ class Bufferhead : public LRUObject { // write_waiters: threads waiting for writes into the buffer list read_waiters, write_waiters; Buffercache *bc; + ref = 0; // cons/destructors Bufferhead(inodeno_t ino, off_t off, size_t len, Buffercache *bc, int state=BUFHD_STATE_CLEAN) { - this->ref = 0; this->ino = ino; this->offset = off; this->len = len; @@ -52,32 +41,41 @@ class Bufferhead : public LRUObject { } ~Bufferhead() { - // no need to delete bufferlist bufferptr's explicitly; ~list() does that (since it's list, not list) + list bl = bh->bl.buffers(); + for (list::iterator it == bl.begin(); + it != bl.end(); + it++) { + delete *it; + } } //Bufferhead(inodeno_t ino, off_t off, size_t len, int state); - // ~Bufferhead(); FIXME: need to mesh with allocator scheme - - - // -- wait for read, write: these will block - // i think this will work okay? and reference coutning in the waiter makes sure the wakeup fn doesn't - // inadvertantly unpin the bufferhead before the waiters get to go - void wait_for_read(Mutex& lock) { - Cond cond; // on local stack - get(); - read_waiters.push_back(&cond); - cond.Wait(lock); - put(); + + void get() { + ref++; + assert(ref > 0); } - void wait_for_write(Mutex& lock) { - Cond cond; // on local stack - get(); - write_waiters.push_back(&cond); - cond.Wait(lock); - put(); + + void put() { + assert (ref > 0); + ref--; + if (ref == 0) { + assert(!lru_pinned); + delete this; + } } + void add_read_waiter(Cond *cond) { + read_waiters->push_back(cond); + lru_pin(); + } + + void add_write_waiter(Cond *cond) { + write_waiters->push_back(cond); + lru_pin(); + } + void wakeup_read_waiters() { for (list::iterator it = read_waiters.begin(); it != read_waiters.end(); @@ -85,6 +83,7 @@ class Bufferhead : public LRUObject { (*it)->Signal(); } read_waiters.clear(); + if (write_waiters.empty()) lru_unpin(); } void wakeup_write_waiters() { @@ -93,6 +92,8 @@ class Bufferhead : public LRUObject { it++) { (*it)->Signal(); } + write_waiters.clear(); + if (read_waiters.empty()) lru_unpin(); } void miss_start() { @@ -112,7 +113,14 @@ class Bufferhead : public LRUObject { state = BUFHD_STATE_DIRTY; bc->dirty_size += bh->len; bc->clean_size -= bh->len; - bc->dirty_map[last_written] = this; + if (bc->dirty_buffers.count(offset)) { + bc->dirty_buffers.insert(this); + get(); + } + if (bc->bcache_map[ino]->dirty_buffers.count(offset)) { + bc->bcache_map[ino]->dirty_buffers.insert(this); + get(); + } } } @@ -126,8 +134,11 @@ class Bufferhead : public LRUObject { void flush_finish() { assert(state == BUFHD_STATE_INFLIGHT); state = BUFHD_STATE_CLEAN; + last_written = time(); bc->flush_size -= len; bc->clean_size += len; + bc->dirty_buffers.erase(this); put(); + bc->bcache_map[ino]->dirty_buffers.erase(this); put(); wakeup_write_waiters(); // readers never wait on flushes } @@ -143,6 +154,8 @@ class Bufferhead : public LRUObject { class Filecache { public: map buffer_map; + set dirty_buffers; + list waitfor_flushed; size_t length() { size_t len = 0; @@ -159,7 +172,7 @@ class Filecache { void map_existing(size_t len, off_t start_off, map& hits, inflight, map& holes); - void simplify(); + void simplify(list& removed); }; @@ -168,8 +181,9 @@ class Buffercache { map bcache_map; LRU lru; size_t dirty_size = 0, flushing_size = 0, clean_size = 0; - map dirty_map; - + set dirty_buffers; + list waitfor_flushed; + // FIXME: constructor & destructor need to mesh with allocator scheme ~Buffercache() { // FIXME: make sure all buffers are cleaned and then free them