#include <list>
using namespace std;
+#include <sys/mman.h>
+
#include "include/buffer.h"
#include "include/bufferlist.h"
-//#undef dout
-//#define dout(x) if (x <= g_conf.debug) cout << "bufferpool "
-
class AlignedBufferPool {
- int buffer_size;
- int num_buffers;
- int num_free;
-
- static const int MIN_ALLOC = 1024*1024;
-
- list<char*> allocated; // my pools
- list<char*> freelist; // my freelist
-
-
+ int alignment; // err, this isn't actually enforced! we just use mmap.
public:
- AlignedBufferPool(int size) : buffer_size(size), num_buffers(0), num_free(0) {}
+ AlignedBufferPool(int a) : alignment(a) {}
~AlignedBufferPool() {
- if (num_free != num_buffers) {
- dout(1) << "WARNING: " << num_buffers-num_free << "/" << num_buffers << " buffers still allocated" << endl;
- }
- for (list<char*>::iterator i = allocated.begin();
- i != allocated.end();
- i++)
- delete[] *i;
}
-
- // individual buffers
- void free(bufferptr& bp) {
- free(bp.c_str());
- }
- void free(char *p) {
- dout(10) << "bufferpool.free " << (void*)p << endl;
- freelist.push_back(p);
- num_free++;
+ void free(char *p, unsigned len) {
+ dout(10) << "bufferpool.free " << (void*)p << " len " << len << endl;
+ munmap(p, len);
}
- static void aligned_buffer_free_func(void *arg, char *ptr) {
+ static void aligned_buffer_free_func(void *arg, char *ptr, unsigned len) {
AlignedBufferPool *pool = (AlignedBufferPool*)arg;
- pool->free(ptr);
+ pool->free(ptr, len);
}
+ buffer *alloc(int bytes) {
+ assert(bytes % alignment == 0);
+ char *p = (char*)mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ assert(p);
- // allocate a single buffer
- buffer* alloc() {
- // get more memory?
- if (freelist.empty()) {
- int get = (num_buffers ? num_buffers:1) * buffer_size;
- if (get < MIN_ALLOC) get = MIN_ALLOC;
-
- char *n = new char[get];
- assert(n);
- memset(n, 0, get);
- allocated.push_back(n);
-
- // add items to freelist
- int num = get / buffer_size;
- char *p = n;
- int misalign = (unsigned)p % buffer_size;
- if (misalign) {
- p += buffer_size - misalign;
- num--;
- }
- dout(2) << "bufferpool.alloc allocated " << get << " bytes, got " << num << " aligned buffers" << endl;
- while (num--) {
- freelist.push_back( p );
- num_free++;
- num_buffers++;
- p += buffer_size;
- }
- }
-
- // allocate one.
- assert(!freelist.empty());
- char *p = freelist.front();
dout(10) << "bufferpool.alloc " << (void*)p << endl;
- freelist.pop_front();
- num_free--;
- return new buffer(p, buffer_size, BUFFER_MODE_NOCOPY|BUFFER_MODE_NOFREE|BUFFER_MODE_CUSTOMFREE,
- buffer_size,
+
+ return new buffer(p, bytes, BUFFER_MODE_NOCOPY|BUFFER_MODE_NOFREE|BUFFER_MODE_CUSTOMFREE,
+ bytes,
aligned_buffer_free_func, this);
}
+ // allocate a single buffer
+ buffer* alloc_page() {
+ return alloc(alignment);
+ }
// bufferlists
- void alloc_list(int n, bufferlist& bl) {
- bl.clear();
- while (n--) {
- bl.push_back(alloc());
- }
- }
- void free_list(bufferlist& bl) {
- for (list<bufferptr>::iterator i = bl.buffers().begin();
- i != bl.buffers().end();
- i++)
- free(*i);
+ void alloc(int bytes, bufferlist& bl) {
bl.clear();
+ bl.push_back( alloc(bytes) );
}
sb.table_nodepool.region_loc[i] = table_nodepool.get_region_loc(i);
}
- bufferptr bp = bufferpool.alloc();
+ bufferptr bp = bufferpool.alloc(EBOFS_BLOCK_SIZE);
memcpy(bp.c_str(), (const char*)&sb, sizeof(sb));
dev.write(bno, 1, bp);
return 0;
// read it!
bufferlist bl;
- bufferpool.alloc_list( onode_loc.length, bl );
+ bufferpool.alloc( EBOFS_BLOCK_SIZE*onode_loc.length, bl );
dev.read( onode_loc.start, onode_loc.length, bl );
// parse data block
unsigned blocks = (bytes-1)/EBOFS_BLOCK_SIZE + 1;
bufferlist bl;
- bufferpool.alloc_list( blocks, bl );
+ bufferpool.alloc( EBOFS_BLOCK_SIZE*blocks, bl );
// place on disk
if (on->onode_loc.length < blocks) {
// read it!
bufferlist bl;
- bufferpool.alloc_list( cnode_loc.length, bl );
+ bufferpool.alloc( EBOFS_BLOCK_SIZE*cnode_loc.length, bl );
dev.read( cnode_loc.start, cnode_loc.length, bl );
// parse data block
unsigned blocks = (bytes-1)/EBOFS_BLOCK_SIZE + 1;
bufferlist bl;
- bufferpool.alloc_list( blocks, bl );
+ bufferpool.alloc( EBOFS_BLOCK_SIZE*blocks, bl );
// place on disk
if (cn->cnode_loc.length < blocks) {
on->map_extents(bh->start(), bh->length(), ex);
// alloc new buffer
- bc.bufferpool.alloc_list(bh->length(), bh->data); // new buffers!
+ bc.bufferpool.alloc(EBOFS_BLOCK_SIZE*bh->length(), bh->data); // new buffers!
// lay out on disk
block_t bhoff = 0;
if (bh->partial_is_complete(on->object_size)) {
dout(10) << "apply_write completed partial " << *bh << endl;
- bc.bufferpool.alloc_list(bh->length(), bh->data); // new buffers!
+ bc.bufferpool.alloc(EBOFS_BLOCK_SIZE*bh->length(), bh->data); // new buffers!
bh->data.zero();
bh->apply_partial();
bc.mark_dirty(bh);
assert(zleft+left >= (off_t)(EBOFS_BLOCK_SIZE*bh->length()));
// alloc new buffers.
- bc.bufferpool.alloc_list(bh->length(), bh->data);
+ bc.bufferpool.alloc(EBOFS_BLOCK_SIZE*bh->length(), bh->data);
// copy!
unsigned len_in_bh = bh->length()*EBOFS_BLOCK_SIZE;
block_t free_blocks;
Allocator allocator;
friend class Allocator;
-
+
// ** buffers **
AlignedBufferPool bufferpool;
-
+
// ** tables and sets **
// nodes
#ifndef __EBOFS_ONODE_H
#define __EBOFS_ONODE_H
-
#include "include/lru.h"
#include "types.h"
#include "BufferCache.h"
-class AttrVal {
- public:
- char *data;
- int len;
- AttrVal() : data(0), len(0) {}
- AttrVal(char *from, int l) :
- len(l) {
- data = new char[len];
- memcpy(data, from, len);
- }
- AttrVal(const AttrVal &other) {
- len = other.len;
- data = new char[len];
- memcpy(data, other.data, len);
- }
- AttrVal& operator=(const AttrVal &other) {
- if (data) delete[] data;
- len = other.len;
- data = new char[len];
- memcpy(data, other.data, len);
- return *this;
- }
- ~AttrVal() {
- delete[] data;
- }
-};
+/*
+ * object node (like an inode)
+ *
+ * holds object metadata, including
+ * size
+ * allocation (extent list)
+ * attributes
+ *
+ */
+
+
class Onode : public LRUObject {
private:
for (block_t boff = 0; boff < r->location.length; boff += EBOFS_NODE_BLOCKS) {
nodeid_t nid = NodeRegion::make_nodeid(r->get_region_id(), boff);
- bufferptr bp = bufferpool.alloc();
+ bufferptr bp = bufferpool.alloc(EBOFS_NODE_BYTES);
dev.read(r->location.start + (block_t)boff, EBOFS_NODE_BLOCKS,
bp);
r->committing = r->limbo;
r->limbo.clear();
- bufferptr freebuffer = bufferpool.alloc();
+ bufferptr freebuffer = bufferpool.alloc(EBOFS_NODE_BYTES);
Node freenode(1, freebuffer);
freenode.set_status(Node::STATUS_FREE);
for (set<int>::iterator i = r->committing.begin();
return -1;
}
Node* new_node() {
- bufferptr bp = bufferpool.alloc();
+ bufferptr bp = bufferpool.alloc(EBOFS_NODE_BYTES);
Node *n = new Node(new_nodeid(), bp);
n->clear();
dbtout << "pool.new_node " << n->get_id() << endl;
#define MAX(a,b) ((a)>=(b) ? (a):(b))
-
/*
- this is to make some of the STL types work with 64 bit values, string hash keys, etc.
- added when i was using an old STL.. maybe try taking these out and see if things
+/*
+ * really simple container for (collection|object) attribute values,
+ * which are a (void*,int) pair. hide associated memory management
+ * ugliness.
+ */
+class AttrVal {
+ public:
+ char *data;
+ int len;
+ AttrVal() : data(0), len(0) {}
+ AttrVal(char *from, int l) :
+ len(l) {
+ data = new char[len];
+ memcpy(data, from, len);
+ }
+ AttrVal(const AttrVal &other) {
+ len = other.len;
+ data = new char[len];
+ memcpy(data, other.data, len);
+ }
+ AttrVal& operator=(const AttrVal &other) {
+ if (data) delete[] data;
+ len = other.len;
+ data = new char[len];
+ memcpy(data, other.data, len);
+ return *this;
+ }
+ ~AttrVal() {
+ delete[] data;
+ }
+};
+
+
#endif
extern long buffer_total_alloc;
-typedef void (buffer_free_func_t)(void*,char*);
+typedef void (buffer_free_func_t)(void*,char*,unsigned);
/*
bdbout(1) << "buffer.des " << *this << endl;
if (free_func) {
bdbout(1) << "buffer.custom_free_func " << free_func_arg << " " << (void*)_dataptr << endl;
- free_func( free_func_arg, _dataptr );
+ free_func( free_func_arg, _dataptr, _alloc_len );
}
else if (_dataptr && _myptr) {
bdbout(1) << "buffer.free " << (void*)_dataptr << endl;