1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-05-12 07:02:09 -05:00

Reimplement alloc_channel_id using search234.

This replaces the previous log(n)^2 algorithm for channel-number
allocation, which binary-searched the space of tree indices using a
log-time call to index234() at each step, with a single log-time pass
down the tree which only has to check the returned channel number
against the returned tree index at each step.

I'm under no illusions that this was a critical performance issue, but
it's been offending my sense of algorithmic elegance for a while.
This commit is contained in:
Simon Tatham 2018-09-19 13:20:03 +01:00
parent b2d0bd0da4
commit 61f18ac451

48
ssh.c
View File

@ -1046,42 +1046,36 @@ static int ssh_rportcmp_ssh2(void *av, void *bv)
return 0; return 0;
} }
static int alloc_channel_id(Ssh ssh) static unsigned alloc_channel_id(Ssh ssh)
{ {
const unsigned CHANNEL_NUMBER_OFFSET = 256; const unsigned CHANNEL_NUMBER_OFFSET = 256;
unsigned low, high, mid; search234_state ss;
int tsize;
struct ssh_channel *c;
/* /*
* First-fit allocation of channel numbers: always pick the * First-fit allocation of channel numbers: we always pick the
* lowest unused one. To do this, binary-search using the * lowest unused one.
* counted B-tree to find the largest channel ID which is in a *
* contiguous sequence from the beginning. (Precisely * Every channel before that, and no channel after it, has an ID
* everything in that sequence must have ID equal to its tree * exactly equal to its tree index plus CHANNEL_NUMBER_OFFSET. So
* index plus CHANNEL_NUMBER_OFFSET.) * we can use the search234 system to identify the length of that
* initial sequence, in a single log-time pass down the channels
* tree.
*/ */
tsize = count234(ssh->channels); search234_start(&ss, ssh->channels);
while (ss.element) {
low = -1; struct ssh_channel *c = (struct ssh_channel *)ss.element;
high = tsize; if (c->localid == ss.index + CHANNEL_NUMBER_OFFSET)
while (high - low > 1) { search234_step(&ss, +1);
mid = (high + low) / 2;
c = index234(ssh->channels, mid);
if (c->localid == mid + CHANNEL_NUMBER_OFFSET)
low = mid; /* this one is fine */
else else
high = mid; /* this one is past it */ search234_step(&ss, -1);
} }
/* /*
* Now low points to either -1, or the tree index of the * Now ss.index gives exactly the number of channels in that
* largest ID in the initial sequence. * initial sequence. So adding CHANNEL_NUMBER_OFFSET to it must
* give precisely the lowest unused channel number.
*/ */
{ return ss.index + CHANNEL_NUMBER_OFFSET;
unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
assert(NULL == find234(ssh->channels, &i, ssh_channelfind));
}
return low + 1 + CHANNEL_NUMBER_OFFSET;
} }
static void c_write_stderr(int trusted, const void *vbuf, int len) static void c_write_stderr(int trusted, const void *vbuf, int len)