scoutfs: sort keys by zone, then inode, then type

Holding a DLM lock protects a range of the key space.  The DLM locks
span inodes or regions of inodes.  We need the sort order in LSM items
to match the DLM range keys so that we can read all the items covered by
a lock into the cache from a region of LSM segments.  If their orders
differered then we'd have to jump around segments to find all the items
covered by a given DLM lock.

Previously we were sorting by type then, within types, by inode.  Now we
want to sort by inode then by type.  But there are structures which
previously had a type but weren't then sorted by inode.  We introduce
zones as the primary sort key.  Inode index and node zones are sorted by
the inode fields and node ids respectively.  Then comes the fs zone
first sorted by inode then the type of the key.

The bulk of this is the mechanical introduction of the zone field to the
keys, moving the type field down, and a bulk rename of _KEY to _TYPE.
But there are some more substantial changes.

The orphan keys needed to be put in a zone.   They fit in the NODE zone
which is all about resources that nodes hold and would need to be
cleaned up if the node went away.

The key formatting is significantly changed to match the new formatting.
Formatted keys are now generally of the form "zone.primary.type..."

And finally with the keys now properly sorted by inodes we can correctly
construct a single range of item cache keys to invalidate when unlocking
the inode group locks.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-07-19 13:30:03 -07:00
parent 690049c293
commit 8d29c82306
10 changed files with 224 additions and 164 deletions
+23 -12
View File
@@ -224,8 +224,9 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode)
void scoutfs_inode_init_key(struct scoutfs_key_buf *key,
struct scoutfs_inode_key *ikey, u64 ino)
{
ikey->type = SCOUTFS_INODE_KEY;
ikey->zone = SCOUTFS_FS_ZONE;
ikey->ino = cpu_to_be64(ino);
ikey->type = SCOUTFS_INODE_TYPE;
scoutfs_key_init(key, ikey, sizeof(struct scoutfs_inode_key));
}
@@ -479,6 +480,7 @@ static int update_index(struct inode *inode, u8 type, u64 now_major,
if (si->have_item && now_major == then_major && now_minor == then_minor)
return 0;
ins_ikey.zone = SCOUTFS_INODE_INDEX_ZONE;
ins_ikey.type = type;
ins_ikey.major = cpu_to_be64(now_major);
ins_ikey.minor = cpu_to_be32(now_minor);
@@ -489,6 +491,7 @@ static int update_index(struct inode *inode, u8 type, u64 now_major,
if (ret || !si->have_item)
return ret;
del_ikey.zone = SCOUTFS_INODE_INDEX_ZONE;
del_ikey.type = type;
del_ikey.major = cpu_to_be64(then_major);
del_ikey.minor = cpu_to_be32(then_minor);
@@ -527,18 +530,18 @@ void scoutfs_update_inode_item(struct inode *inode)
/* set the meta version once per trans for any inode updates */
scoutfs_inode_set_meta_seq(inode);
ret = update_index(inode, SCOUTFS_INODE_INDEX_CTIME_KEY,
ret = update_index(inode, SCOUTFS_INODE_INDEX_CTIME_TYPE,
inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
si->item_ctime.tv_sec, si->item_ctime.tv_nsec) ?:
update_index(inode, SCOUTFS_INODE_INDEX_MTIME_KEY,
update_index(inode, SCOUTFS_INODE_INDEX_MTIME_TYPE,
inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
si->item_mtime.tv_sec, si->item_mtime.tv_nsec) ?:
update_index(inode, SCOUTFS_INODE_INDEX_SIZE_KEY,
update_index(inode, SCOUTFS_INODE_INDEX_SIZE_TYPE,
i_size_read(inode), 0, si->item_size, 0) ?:
update_index(inode, SCOUTFS_INODE_INDEX_META_SEQ_KEY,
update_index(inode, SCOUTFS_INODE_INDEX_META_SEQ_TYPE,
scoutfs_inode_meta_seq(inode), 0,
si->item_meta_seq, 0) ?:
update_index(inode, SCOUTFS_INODE_INDEX_DATA_SEQ_KEY,
update_index(inode, SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE,
scoutfs_inode_data_seq(inode), 0,
si->item_data_seq, 0);
BUG_ON(ret);
@@ -753,9 +756,11 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir,
}
static void init_orphan_key(struct scoutfs_key_buf *key,
struct scoutfs_orphan_key *okey, u64 ino)
struct scoutfs_orphan_key *okey, u64 node_id, u64 ino)
{
okey->type = SCOUTFS_ORPHAN_KEY;
okey->zone = SCOUTFS_NODE_ZONE;
okey->node_id = cpu_to_be64(node_id);
okey->type = SCOUTFS_ORPHAN_TYPE;
okey->ino = cpu_to_be64(ino);
scoutfs_key_init(key, okey, sizeof(struct scoutfs_orphan_key));
@@ -763,11 +768,12 @@ static void init_orphan_key(struct scoutfs_key_buf *key,
static int remove_orphan_item(struct super_block *sb, u64 ino)
{
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
struct scoutfs_orphan_key okey;
struct scoutfs_key_buf key;
int ret;
init_orphan_key(&key, &okey, ino);
init_orphan_key(&key, &okey, sbi->node_id, ino);
ret = scoutfs_item_delete(sb, &key);
if (ret == -ENOENT)
@@ -907,9 +913,13 @@ static int process_orphaned_inode(struct super_block *sb, u64 ino)
* Runtime of this will be bounded by the number of orphans, which could
* theoretically be very large. If that becomes a problem we might want to push
* this work off to a thread.
*
* This only scans orphans for this node. This will need to be covered by
* the rest of node zone cleanup.
*/
int scoutfs_scan_orphans(struct super_block *sb)
{
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
struct scoutfs_orphan_key okey;
struct scoutfs_orphan_key last_okey;
struct scoutfs_key_buf key;
@@ -919,8 +929,8 @@ int scoutfs_scan_orphans(struct super_block *sb)
trace_scoutfs_scan_orphans(sb);
init_orphan_key(&key, &okey, 0);
init_orphan_key(&last, &last_okey, ~0ULL);
init_orphan_key(&key, &okey, sbi->node_id, 0);
init_orphan_key(&last, &last_okey, sbi->node_id, ~0ULL);
while (1) {
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
@@ -944,13 +954,14 @@ out:
int scoutfs_orphan_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
struct scoutfs_orphan_key okey;
struct scoutfs_key_buf key;
int ret;
trace_scoutfs_orphan_inode(sb, inode);
init_orphan_key(&key, &okey, scoutfs_ino(inode));
init_orphan_key(&key, &okey, sbi->node_id, scoutfs_ino(inode));
ret = scoutfs_item_create(sb, &key, NULL);