lib/libvarnish/vbh.c
void
VBH_delete(struct vbh *bh, unsigned idx)
{

	CHECK_OBJ_NOTNULL(bh, VBH_MAGIC);
	assert(bh->next > ROOT_IDX);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);
	bh->update(bh->priv, A(bh, idx), VBH_NOIDX);
	if (idx == --bh->next) {
		A(bh, bh->next) = NULL;
		return;
	}
	A(bh, idx) = A(bh, bh->next);
	A(bh, bh->next) = NULL;
	vbh_update(bh, idx);
	idx = vbh_trickleup(bh, idx);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);
	idx = vbh_trickledown(bh, idx);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);

	/*
	 * We keep a hysteresis of one full row before we start to
	 * return space to the OS to avoid silly behaviour around
	 * row boundaries.
	 */
	if (bh->next + 2 * ROW_WIDTH <= bh->length) {
		free(ROW(bh, bh->length - 1));
		ROW(bh, bh->length - 1) = NULL;
		bh->length -= ROW_WIDTH;
	}
}
/*
 * It may seem counter-intuitive that we delete by replacement with
 * the tail object. "That's almost certain to not belong there, in
 * particular when we delete the root ?" is the typical reaction.
 *
 * If we tried to trickle up into the empty position, we would,
 * eventually, end up with a hole in the bottom row, at which point
 * we would move the tail object there.
 * But there is no guarantee that the tail object would not need to
 * trickle up from that position, in fact, it might be the new root
 * of this half of the subtree.
 * The total number of operations is guaranteed to be at least
 * N{height} downward selections, because we have to get the hole
 * all the way down, but in addition to that, we may get up to
 * N{height}-1 upward trickles.
 *
 * When we fill the hole with the tail object, the worst case is
 * that it trickles all the way up to of this half-tree, or down
 * to become the tail object again.
 *
 * In other words worst case is N{height} up or downward trickles.
 * But there is a decent chance that it does not make it all the way.
 */
It may seem counter-intuitive that we delete by replacement with
the tail object. "That's almost certain to not belong there, in
particular when we delete the root ?" is the typical reaction.

If we tried to trickle up into the empty position, we would,
eventually, end up with a hole in the bottom row, at which point
we would move the tail object there.
But there is no guarantee that the tail object would not need to
trickle up from that position, in fact, it might be the new root
of this half of the subtree.
The total number of operations is guaranteed to be at least
N{height} downward selections, because we have to get the hole
all the way down, but in addition to that, we may get up to
N{height}-1 upward trickles.

When we fill the hole with the tail object, the worst case is
that it trickles all the way up to of this half-tree, or down
to become the tail object again.

In other words worst case is N{height} up or downward trickles.
But there is a decent chance that it does not make it all the way.
It may seem counter - intuitive that we delete by replacement with the tail object . " That ' s almost certain to not belong there in particular when we delete the root ? " is the typical reaction . If we tried to trickle up into the empty position we would eventually end up with a hole in the bottom row at which point we would move the tail object there . But there is no guarantee that the tail object would not need to trickle up from that position in fact it might be the new root of this half of the subtree . The total number of operations is guaranteed to be at least N { height } downward selections because we have to get the hole all the way down but in addition to that we may get up to N { height } - 1 upward trickles . When we fill the hole with the tail object the worst case is that it trickles all the way up to of this half - tree or down to become the tail object again . In other words worst case is N { height } up or downward trickles . But there is a decent chance that it does not make it all the way .
void
VBH_delete(struct vbh *bh, unsigned idx)
{
	CHECK_OBJ_NOTNULL(bh, VBH_MAGIC);
	assert(bh->next > ROOT_IDX);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);
	bh->update(bh->priv, A(bh, idx), VBH_NOIDX);
	if (idx == --bh->next) {
		A(bh, bh->next) = NULL;
		return;
	}
	A(bh, idx) = A(bh, bh->next);
	A(bh, bh->next) = NULL;
	vbh_update(bh, idx);
	idx = vbh_trickleup(bh, idx);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);
	idx = vbh_trickledown(bh, idx);
	assert(idx < bh->next);
	assert(idx > 0);
	assert(A(bh, idx) != NULL);
	if (bh->next + 2 * ROW_WIDTH <= bh->length) {
		free(ROW(bh, bh->length - 1));
		ROW(bh, bh->length - 1) = NULL;
		bh->length -= ROW_WIDTH;
	}
}
void VBH_delete ( struct vbh * bh , unsigned idx ) { CHECK_OBJ_NOTNULL ( bh , VBH_MAGIC ) ; assert ( bh -> next > ROOT_IDX ) ; assert ( idx < bh -> next ) ; assert ( idx > 0 ) ; assert ( A ( bh , idx ) != NULL ) ; bh -> update ( bh -> priv , A ( bh , idx ) , VBH_NOIDX ) ; if ( idx == -- bh -> next ) { A ( bh , bh -> next ) = NULL ; return ; } A ( bh , idx ) = A ( bh , bh -> next ) ; A ( bh , bh -> next ) = NULL ; vbh_update ( bh , idx ) ; idx = vbh_trickleup ( bh , idx ) ; assert ( idx < bh -> next ) ; assert ( idx > 0 ) ; assert ( A ( bh , idx ) != NULL ) ; idx = vbh_trickledown ( bh , idx ) ; assert ( idx < bh -> next ) ; assert ( idx > 0 ) ; assert ( A ( bh , idx ) != NULL ) ; if ( bh -> next + 2 * ROW_WIDTH <= bh -> length ) { free ( ROW ( bh , bh -> length - 1 ) ) ; ROW ( bh , bh -> length - 1 ) = NULL ; bh -> length -= ROW_WIDTH ; } }
It may seem counter-intuitive that we delete by replacement with
 the tail object.
It may seem counter - intuitive that we delete by replacement with the tail object .
/*
	 * We keep a hysteresis of one full row before we start to
	 * return space to the OS to avoid silly behaviour around
	 * row boundaries.
	 */