assert(p->first == bh->start());
// past?
- if (p->first >= start+length) break;
+ if (p->first >= start+length) {
+ bh->oc->try_merge_bh_right(p);
+ break;
+ }
if (bh->tx_ioh == ioh)
bh->tx_ioh = 0;
assert(bh->end() <= start+length);
bh->set_last_flushed(version);
bc->mark_clean(bh);
+ bh->oc->try_merge_bh_left(p);
} else {
dout(10) << "tx_finish leaving tx, " << bh->version << " > " << version
<< " on " << *bh << dendl;
+BufferHead *ObjectCache::merge_bh_left(BufferHead *left, BufferHead *right)
+{
+ dout(-10) << "merge_bh_left " << *left << " " << *right << dendl;
+ assert(left->end() == right->start());
+ assert(left->is_clean());
+ assert(right->is_clean());
+ assert(right->get_num_ref() == 0);
+
+ // hrm, is this right?
+ if (right->version > left->version) left->version = right->version;
+ if (right->last_flushed > left->last_flushed) left->last_flushed = right->last_flushed;
+
+ left->set_length(left->length() + right->length());
+ left->data.claim_append(right->data);
+
+ // remove right
+ remove_bh(right);
+ bc->lru_rest.lru_remove(right);
+ delete right;
+ dout(-10) << "merge_bh_left result " << *left << dendl;
+ return left;
+}
+
+/* wait until this has a user
+void ObjectCache::try_merge_bh(BufferHead *bh)
+{
+ dout(-10) << "try_merge_bh " << *bh << dendl;
+
+ map<block_t, BufferHead*>::iterator p = data.lower_bound(bh->start());
+ assert(p->second == bh);
+
+ try_merge_bh_left(p);
+ try_merge_bh_right(p);
+}
+*/
+
+
+void ObjectCache::try_merge_bh_left(map<block_t, BufferHead*>::iterator& p)
+{
+ BufferHead *bh = p->second;
+ dout(10) << "try_merge_bh_left " << *bh << dendl;
+
+ // left?
+ if (p != data.begin()) {
+ p--;
+ if (p->second->end() == bh->start() &&
+ p->second->is_clean() &&
+ bh->is_clean() &&
+ bh->get_num_ref() == 0)
+ bh = merge_bh_left(p->second, bh); // yay!
+ else
+ p++; // nope.
+ }
+}
+
+void ObjectCache::try_merge_bh_right(map<block_t, BufferHead*>::iterator& p)
+{
+ BufferHead *bh = p->second;
+ dout(10) << "try_merge_bh_right " << *bh << dendl;
+
+ // right?
+ map<block_t, BufferHead*>::iterator o = p;
+ p++;
+ if (p != data.end() &&
+ bh->end() == p->second->start() &&
+ p->second->is_clean() &&
+ bh->is_clean() &&
+ p->second->get_num_ref() == 0) {
+ BufferHead *right = p->second;
+ p--;
+ merge_bh_left(bh, right);
+ } else
+ p = o;
+}
+
+
+
/************** BufferCache ***************/
#undef dout
}
+
+
void BufferCache::bh_read(Onode *on, BufferHead *bh, block_t from)
{
dout(10) << "bh_read " << *on << " on " << *bh << dendl;
#include "BlockDevice.h"
#include "include/interval_set.h"
+#include "include/xlist.h"
class ObjectCache;
class BufferCache;
set<BufferHead*> shadows; // shadow bh's that clone()ed me.
BufferHead* shadow_of;
+
private:
int ref;
int state;
Extent object_loc; // block position _in_object_
utime_t dirty_stamp;
+ //xlist<BufferHead*>::item xlist_dirty;
bool want_to_expire; // wants to be at bottom of lru
rx_ioh(0), tx_ioh(0), tx_block(0), partial_tx_to(0), partial_tx_epoch(0),
shadow_of(0),
ref(0), state(STATE_MISSING), epoch_modified(0), version(0), last_flushed(0),
+ //xlist_dirty(this),
want_to_expire(false)
{}
~BufferHead() {
--ref;
return ref;
}
+ int get_num_ref() { return ref; }
block_t start() { return object_loc.start; }
void set_start(block_t s) { object_loc.start = s; }
continue;
}
// overlap tail of i?
- if (off > i->first && off < i->first + i->second.length()) {
+ if (off > i->first && off+len >= i->first + i->second.length()) {
// shorten i.
bufferlist o;
o.claim( i->second );
continue;
}
// overlap head of i?
- if (off < i->first && off+len < i->first + i->second.length()) {
+ if (off <= i->first && off+len < i->first + i->second.length()) {
// move i (make new tail).
off_t tailoff = off+len;
unsigned trim = tailoff - i->first;
partial[off] = p;
}
-
};
inline ostream& operator<<(ostream& out, BufferHead& bh)
}
bool is_empty() { return data.empty(); }
+ void try_merge_bh(BufferHead *bh);
+ void try_merge_bh_left(map<block_t, BufferHead*>::iterator& p);
+ void try_merge_bh_right(map<block_t, BufferHead*>::iterator& p);
+ BufferHead* merge_bh_left(BufferHead *left, BufferHead *right);
+
int find_tx(block_t start, block_t len,
list<BufferHead*>& tx);
Mutex &ebofs_lock; // hack: this is a ref to global ebofs_lock
BlockDevice &dev;
- set<BufferHead*> dirty_bh;
+ //xlist<BufferHead*> dirty_bh;
LRU lru_dirty, lru_rest;
bh->get_oc()->add_bh(bh);
if (bh->is_dirty()) {
lru_dirty.lru_insert_mid(bh);
- dirty_bh.insert(bh);
+ //dirty_bh.push_back(&bh->xlist_dirty);
} else
lru_rest.lru_insert_mid(bh);
stat_add(bh);
stat_sub(bh);
if (bh->is_dirty()) {
lru_dirty.lru_remove(bh);
- dirty_bh.erase(bh);
+ //dirty_bh.push_back(&bh->xlist_dirty);
} else
lru_rest.lru_remove(bh);
}
if (s == BufferHead::STATE_DIRTY && bh->get_state() != BufferHead::STATE_DIRTY) {
lru_rest.lru_remove(bh);
lru_dirty.lru_insert_top(bh);
- dirty_bh.insert(bh);
+ //dirty_bh.push_back(&bh->xlist_dirty);
}
if (s != BufferHead::STATE_DIRTY && bh->get_state() == BufferHead::STATE_DIRTY) {
lru_dirty.lru_remove(bh);
lru_rest.lru_insert_bot(bh);
else
lru_rest.lru_insert_mid(bh);
- dirty_bh.erase(bh);
+ //dirty_bh.remove(&bh->xlist_dirty);
}
// set state