forked from Imagelibrary/littlefs
Tweaked always-follow alts to follow even for 0 tags
Changed always-follow alts that we use to terminated grow/shrink/remove operations to use `altle 0xfff0` instead of `altgt 0`. `altgt 0` gets the job done as long as you make sure tag 0 never ends up in an rbyd query. But this kept showing up as a problem, and recent debugging revealed some erronous 0 tag lookups created vestigial alt pointers (not necessarily a problem, but space-wasting). Since we moved to a strict 16-bit tag, making these `altle 0xfff0` doesn't really have a downside, and means we can expect rbyd lookups around 0 to behave how one would normally expect. As a (very minor) plus, the value zero usually has special encodings in instruction sets, so being able to use it for rbyd_lookups offers a (very minor) code size saving. --- Sidenote: The reasons altle/altgt is how it is and asymmetric: 1. Flipping these alts is a single bit-flip, which only happens if they are asymmetric (only one includes the equal case). 2. Our branches are biased to prefer the larger tag. This makes traversal trivial. It might be possible to make this still work with altlt/altge, but would require some increments/decrements, which might cause problems with boundary conditions around the 16-bit tag limit.
This commit is contained in:
16
lfs.c
16
lfs.c
@@ -1504,10 +1504,6 @@ static int lfsr_rbyd_lookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
lfsr_tag_t *tag_, lfs_ssize_t *id_, lfs_size_t *weight_,
|
||||
// TODO should this take lfsr_data_t for consistency?
|
||||
lfs_off_t *off_, lfs_size_t *size_) {
|
||||
// tag must be non-zero! zero tags may deceptively look like they work but
|
||||
// fail when the tree contains a deleted id0
|
||||
LFS_ASSERT(tag != 0);
|
||||
|
||||
// keep track of bounds as we descend down the tree
|
||||
lfs_off_t branch = rbyd->trunk;
|
||||
lfs_ssize_t lower = -1;
|
||||
@@ -2284,13 +2280,13 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||
|
||||
} else if (tag == LFSR_TAG_GROW) {
|
||||
// decrease weight when growing
|
||||
alt = LFSR_TAG_ALT(B, GT, 0);
|
||||
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
|
||||
weight = upper_id - lower_id - 1 + lfsr_data_len(data);
|
||||
|
||||
} else if (tag == LFSR_TAG_SHRINK) {
|
||||
// decrease weight when shrinking
|
||||
if (upper_id - lower_id - 1 > (lfs_ssize_t)lfsr_data_len(data)) {
|
||||
alt = LFSR_TAG_ALT(B, GT, 0);
|
||||
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
|
||||
weight = upper_id - lower_id - 1 - lfsr_data_len(data);
|
||||
}
|
||||
|
||||
@@ -2298,7 +2294,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||
|| (id_ == id && lfsr_tag_key(tag_) > lfsr_tag_key(tag))) {
|
||||
if (lfsr_tag_isrm(tag)) {
|
||||
// hide our tag during removes
|
||||
alt = LFSR_TAG_ALT(B, GT, 0);
|
||||
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
|
||||
weight = upper_id - lower_id - 1;
|
||||
} else {
|
||||
// split greater than
|
||||
@@ -2638,7 +2634,7 @@ static lfs_ssize_t lfsr_btree_lookup(lfs_t *lfs,
|
||||
lfs_size_t weight__;
|
||||
lfs_off_t off_;
|
||||
lfs_size_t size_;
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, LFSR_TAG_NAME, rid,
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, 0, rid,
|
||||
&tag__, &rid__, &weight__, &off_, &size_);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -2736,7 +2732,7 @@ static int lfsr_btree_parent(lfs_t *lfs,
|
||||
lfs_size_t weight__;
|
||||
lfs_off_t off_;
|
||||
lfs_size_t size_;
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, LFSR_TAG_NAME, rid,
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, 0, rid,
|
||||
&tag__, &rid__, &weight__, &off_, &size_);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
@@ -2860,7 +2856,7 @@ static lfs_ssize_t lfsr_btree_find_(lfs_t *lfs,
|
||||
lfs_size_t weight__;
|
||||
lfs_off_t off_;
|
||||
lfs_size_t size_;
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, LFSR_TAG_NAME, find.found_id,
|
||||
err = lfsr_rbyd_lookup(lfs, &rbyd, 0, find.found_id,
|
||||
&tag__, &rid__, &weight__, &off_, &size_);
|
||||
if (err) {
|
||||
return err;
|
||||
|
||||
@@ -309,7 +309,7 @@ def main(disk, block_size=None, trunk=0, limit=None, *,
|
||||
while True:
|
||||
# first lookup id/name
|
||||
(done, name_tag, rid_, w,
|
||||
name_j, name_d, name) = rbyd.lookup(TAG_NAME, rid)
|
||||
name_j, name_d, name) = rbyd.lookup(0, rid)
|
||||
if done:
|
||||
return (True, id, 0, rbyd, -1, 0,
|
||||
0, 0, b'',
|
||||
|
||||
@@ -2237,7 +2237,7 @@ code = '''
|
||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4,
|
||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2251,7 +2251,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2271,7 +2271,7 @@ code = '''
|
||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4,
|
||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2285,7 +2285,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2330,7 +2330,7 @@ code = '''
|
||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||
LFSR_ATTR(UATTR(2), -1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2344,7 +2344,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2365,7 +2365,7 @@ code = '''
|
||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||
LFSR_ATTR(UATTR(1), -1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -2379,7 +2379,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(1));
|
||||
assert(id_ == -1);
|
||||
@@ -4424,7 +4424,7 @@ code = '''
|
||||
LFSR_ATTR(GROW, 1, NULL, 1,
|
||||
LFSR_ATTR(REG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4442,7 +4442,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4468,7 +4468,7 @@ code = '''
|
||||
LFSR_ATTR(GROW, 0, NULL, 1,
|
||||
LFSR_ATTR(REG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4486,7 +4486,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4538,7 +4538,7 @@ code = '''
|
||||
LFSR_ATTR(GROW, 1, NULL, 1,
|
||||
LFSR_ATTR(REG, 1, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4556,7 +4556,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4583,7 +4583,7 @@ code = '''
|
||||
LFSR_ATTR(GROW, 0, NULL, 1,
|
||||
LFSR_ATTR(REG, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -4601,7 +4601,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5679,7 +5679,7 @@ code = '''
|
||||
LFSR_ATTR(REG, 1, "\xbb\xbb\xbb\xbb", 4,
|
||||
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL))))))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5711,7 +5711,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5753,7 +5753,7 @@ code = '''
|
||||
LFSR_ATTR(REG, 0, "\xaa\xaa\xaa\xaa", 4,
|
||||
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL))))))) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5785,7 +5785,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5855,7 +5855,7 @@ code = '''
|
||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||
LFSR_ATTR(UATTR(1), 1, "\xbb\xbb", 2, NULL)) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5887,7 +5887,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5932,7 +5932,7 @@ code = '''
|
||||
lfsr_rbyd_commit(&lfs, &rbyd,
|
||||
LFSR_ATTR(UATTR(1), 0, "\xaa\xaa", 2, NULL)) => 0;
|
||||
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -5964,7 +5964,7 @@ code = '''
|
||||
&tag_, &id_, NULL, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, NULL, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -8929,7 +8929,7 @@ code = '''
|
||||
NULL))))))))))) => 0;
|
||||
|
||||
// traverse, finding tags and weights
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -8963,7 +8963,7 @@ code = '''
|
||||
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_REG);
|
||||
assert(id_ == 0);
|
||||
@@ -9927,7 +9927,7 @@ code = '''
|
||||
NULL)))))))))))))))))))))))))) => 0;
|
||||
|
||||
// traverse, finding tags and weights
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(3));
|
||||
assert(id_ == -1);
|
||||
@@ -10027,7 +10027,7 @@ code = '''
|
||||
&tag_, &id_, &weight_, &off_, &size_) => LFS_ERR_NOENT;
|
||||
|
||||
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.block, cfg->block_size, NULL) => 0;
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, lfsr_tag_next(0), -1,
|
||||
lfsr_rbyd_lookup(&lfs, &rbyd, 0, -1,
|
||||
&tag_, &id_, &weight_, &off_, &size_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(3));
|
||||
assert(id_ == -1);
|
||||
|
||||
Reference in New Issue
Block a user