Commit 6b06dd5a authored by Joe Thornber's avatar Joe Thornber Committed by Mike Snitzer

dm space map disk: cache a small number of index entries

The disk space map stores it's index entries in a btree, these are
accessed very frequently, so having a few cached makes a big difference
to performance.

With this change provisioning a new block takes roughly 20% less cpu.
Signed-off-by: default avatarJoe Thornber <ejt@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent be500ed7
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "dm-space-map-common.h" #include "dm-space-map-common.h"
#include "dm-transaction-manager.h" #include "dm-transaction-manager.h"
#include "dm-btree-internal.h" #include "dm-btree-internal.h"
#include "dm-persistent-data-internal.h"
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/device-mapper.h> #include <linux/device-mapper.h>
...@@ -1083,28 +1084,92 @@ int sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm, ...@@ -1083,28 +1084,92 @@ int sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm,
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
static inline int ie_cache_writeback(struct ll_disk *ll, struct ie_cache *iec)
{
iec->dirty = false;
__dm_bless_for_disk(iec->ie);
return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root,
&iec->index, &iec->ie, &ll->bitmap_root);
}
static inline unsigned hash_index(dm_block_t index)
{
return dm_hash_block(index, IE_CACHE_MASK);
}
static int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index, static int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie) struct disk_index_entry *ie)
{ {
return dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie); int r;
unsigned h = hash_index(index);
struct ie_cache *iec = ll->ie_cache + h;
if (iec->valid) {
if (iec->index == index) {
memcpy(ie, &iec->ie, sizeof(*ie));
return 0;
}
if (iec->dirty) {
r = ie_cache_writeback(ll, iec);
if (r)
return r;
}
}
r = dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie);
if (!r) {
iec->valid = true;
iec->dirty = false;
iec->index = index;
memcpy(&iec->ie, ie, sizeof(*ie));
}
return r;
} }
static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index, static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie) struct disk_index_entry *ie)
{ {
__dm_bless_for_disk(ie); int r;
return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root, unsigned h = hash_index(index);
&index, ie, &ll->bitmap_root); struct ie_cache *iec = ll->ie_cache + h;
ll->bitmap_index_changed = true;
if (iec->valid) {
if (iec->index == index) {
memcpy(&iec->ie, ie, sizeof(*ie));
iec->dirty = true;
return 0;
}
if (iec->dirty) {
r = ie_cache_writeback(ll, iec);
if (r)
return r;
}
}
iec->valid = true;
iec->dirty = true;
iec->index = index;
memcpy(&iec->ie, ie, sizeof(*ie));
return 0;
} }
static int disk_ll_init_index(struct ll_disk *ll) static int disk_ll_init_index(struct ll_disk *ll)
{ {
unsigned i;
for (i = 0; i < IE_CACHE_SIZE; i++) {
struct ie_cache *iec = ll->ie_cache + i;
iec->valid = false;
iec->dirty = false;
}
return dm_btree_empty(&ll->bitmap_info, &ll->bitmap_root); return dm_btree_empty(&ll->bitmap_info, &ll->bitmap_root);
} }
static int disk_ll_open(struct ll_disk *ll) static int disk_ll_open(struct ll_disk *ll)
{ {
/* nothing to do */
return 0; return 0;
} }
...@@ -1115,7 +1180,16 @@ static dm_block_t disk_ll_max_entries(struct ll_disk *ll) ...@@ -1115,7 +1180,16 @@ static dm_block_t disk_ll_max_entries(struct ll_disk *ll)
static int disk_ll_commit(struct ll_disk *ll) static int disk_ll_commit(struct ll_disk *ll)
{ {
return 0; int r = 0;
unsigned i;
for (i = 0; i < IE_CACHE_SIZE; i++) {
struct ie_cache *iec = ll->ie_cache + i;
if (iec->valid && iec->dirty)
r = ie_cache_writeback(ll, iec);
}
return r;
} }
int sm_ll_new_disk(struct ll_disk *ll, struct dm_transaction_manager *tm) int sm_ll_new_disk(struct ll_disk *ll, struct dm_transaction_manager *tm)
......
...@@ -54,6 +54,20 @@ typedef int (*open_index_fn)(struct ll_disk *ll); ...@@ -54,6 +54,20 @@ typedef int (*open_index_fn)(struct ll_disk *ll);
typedef dm_block_t (*max_index_entries_fn)(struct ll_disk *ll); typedef dm_block_t (*max_index_entries_fn)(struct ll_disk *ll);
typedef int (*commit_fn)(struct ll_disk *ll); typedef int (*commit_fn)(struct ll_disk *ll);
/*
* A lot of time can be wasted reading and writing the same
* index entry. So we cache a few entries.
*/
#define IE_CACHE_SIZE 64
#define IE_CACHE_MASK (IE_CACHE_SIZE - 1)
struct ie_cache {
bool valid;
bool dirty;
dm_block_t index;
struct disk_index_entry ie;
};
struct ll_disk { struct ll_disk {
struct dm_transaction_manager *tm; struct dm_transaction_manager *tm;
struct dm_btree_info bitmap_info; struct dm_btree_info bitmap_info;
...@@ -79,6 +93,8 @@ struct ll_disk { ...@@ -79,6 +93,8 @@ struct ll_disk {
max_index_entries_fn max_entries; max_index_entries_fn max_entries;
commit_fn commit; commit_fn commit;
bool bitmap_index_changed:1; bool bitmap_index_changed:1;
struct ie_cache ie_cache[IE_CACHE_SIZE];
}; };
struct disk_sm_root { struct disk_sm_root {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment