Commit 07ac4cdb authored by Fam Zheng's avatar Fam Zheng Committed by Max Reitz
Browse files

HBitmap: Introduce "meta" bitmap to track bit changes



Upon each bit toggle, the corresponding bit in the meta bitmap will be
set.

Signed-off-by: default avatarFam Zheng <famz@redhat.com>
[Amended text inline. --js]
Reviewed-by: default avatarMax Reitz <mreitz@redhat.com>

Signed-off-by: default avatarJohn Snow <jsnow@redhat.com>
Message-id: 1476395910-8697-3-git-send-email-jsnow@redhat.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent dc162c8e
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -178,6 +178,27 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
 */
unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);

/* hbitmap_create_meta:
 * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap.
 * The caller owns the created bitmap and must call hbitmap_free_meta(hb) to
 * free it.
 *
 * Currently, we only guarantee that if a bit in the hbitmap is changed it
 * will be reflected in the meta bitmap, but we do not yet guarantee the
 * opposite.
 *
 * @hb: The HBitmap to operate on.
 * @chunk_size: How many bits in @hb does one bit in the meta track.
 */
HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size);

/* hbitmap_free_meta:
 * Free the meta bitmap of @hb.
 *
 * @hb: The HBitmap whose meta bitmap should be freed.
 */
void hbitmap_free_meta(HBitmap *hb);

/**
 * hbitmap_iter_next:
 * @hbi: HBitmapIter to operate on.
+54 −15
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@ struct HBitmap {
     */
    int granularity;

    /* A meta dirty bitmap to track the dirtiness of bits in this HBitmap. */
    HBitmap *meta;

    /* A number of progressively less coarse bitmaps (i.e. level 0 is the
     * coarsest).  Each bit in level N represents a word in level N+1 that
     * has a set bit, except the last level where each bit represents the
@@ -209,25 +212,27 @@ static uint64_t hb_count_between(HBitmap *hb, uint64_t start, uint64_t last)
}

/* Setting starts at the last layer and propagates up if an element
 * changes from zero to non-zero.
 * changes.
 */
static inline bool hb_set_elem(unsigned long *elem, uint64_t start, uint64_t last)
{
    unsigned long mask;
    bool changed;
    unsigned long old;

    assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL));
    assert(start <= last);

    mask = 2UL << (last & (BITS_PER_LONG - 1));
    mask -= 1UL << (start & (BITS_PER_LONG - 1));
    changed = (*elem == 0);
    old = *elem;
    *elem |= mask;
    return changed;
    return old != *elem;
}

/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
 * Returns true if at least one bit is changed. */
static bool hb_set_between(HBitmap *hb, int level, uint64_t start,
                           uint64_t last)
{
    size_t pos = start >> BITS_PER_LEVEL;
    size_t lastpos = last >> BITS_PER_LEVEL;
@@ -256,23 +261,28 @@ static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last
    if (level > 0 && changed) {
        hb_set_between(hb, level - 1, pos, lastpos);
    }
    return changed;
}

void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count)
{
    /* Compute range in the last layer.  */
    uint64_t first, n;
    uint64_t last = start + count - 1;

    trace_hbitmap_set(hb, start, count,
                      start >> hb->granularity, last >> hb->granularity);

    start >>= hb->granularity;
    first = start >> hb->granularity;
    last >>= hb->granularity;
    count = last - start + 1;
    assert(last < hb->size);
    n = last - first + 1;

    hb->count += count - hb_count_between(hb, start, last);
    hb_set_between(hb, HBITMAP_LEVELS - 1, start, last);
    hb->count += n - hb_count_between(hb, first, last);
    if (hb_set_between(hb, HBITMAP_LEVELS - 1, first, last) &&
        hb->meta) {
        hbitmap_set(hb->meta, start, count);
    }
}

/* Resetting works the other way round: propagate up if the new
@@ -293,8 +303,10 @@ static inline bool hb_reset_elem(unsigned long *elem, uint64_t start, uint64_t l
    return blanked;
}

/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
 * Returns true if at least one bit is changed. */
static bool hb_reset_between(HBitmap *hb, int level, uint64_t start,
                             uint64_t last)
{
    size_t pos = start >> BITS_PER_LEVEL;
    size_t lastpos = last >> BITS_PER_LEVEL;
@@ -337,22 +349,29 @@ static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t la
    if (level > 0 && changed) {
        hb_reset_between(hb, level - 1, pos, lastpos);
    }

    return changed;

}

void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
{
    /* Compute range in the last layer.  */
    uint64_t first;
    uint64_t last = start + count - 1;

    trace_hbitmap_reset(hb, start, count,
                        start >> hb->granularity, last >> hb->granularity);

    start >>= hb->granularity;
    first = start >> hb->granularity;
    last >>= hb->granularity;
    assert(last < hb->size);

    hb->count -= hb_count_between(hb, start, last);
    hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last);
    hb->count -= hb_count_between(hb, first, last);
    if (hb_reset_between(hb, HBITMAP_LEVELS - 1, first, last) &&
        hb->meta) {
        hbitmap_set(hb->meta, start, count);
    }
}

void hbitmap_reset_all(HBitmap *hb)
@@ -381,6 +400,7 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
void hbitmap_free(HBitmap *hb)
{
    unsigned i;
    assert(!hb->meta);
    for (i = HBITMAP_LEVELS; i-- > 0; ) {
        g_free(hb->levels[i]);
    }
@@ -458,6 +478,9 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size)
                   (size - old) * sizeof(*hb->levels[i]));
        }
    }
    if (hb->meta) {
        hbitmap_truncate(hb->meta, hb->size << hb->granularity);
    }
}


@@ -493,3 +516,19 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b)

    return true;
}

HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size)
{
    assert(!(chunk_size & (chunk_size - 1)));
    assert(!hb->meta);
    hb->meta = hbitmap_alloc(hb->size << hb->granularity,
                             hb->granularity + ctz32(chunk_size));
    return hb->meta;
}

void hbitmap_free_meta(HBitmap *hb)
{
    assert(hb->meta);
    hbitmap_free(hb->meta);
    hb->meta = NULL;
}