relay: improve the way we allocate channels
Now the server allocates a channel randomly from set of available ids with the shortest possible length. So concurrency=1 will always yield a channel-id between 1 and 9 (inclusive). If we have 9 simultaneous sessions, we'll start allocating channels from 10 to 99. 100 simultaneous connections kicks us into the 100-999 bucket, etc.
This commit is contained in:
parent
ecc04ff675
commit
c8d2fc8750
|
@ -1,5 +1,5 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import re, json, time
|
import re, json, time, random
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from twisted.internet import protocol
|
from twisted.internet import protocol
|
||||||
from twisted.application import strports, service, internet
|
from twisted.application import strports, service, internet
|
||||||
|
@ -56,13 +56,12 @@ WELCOME = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# relay URLs are:
|
# relay URLs are:
|
||||||
#
|
# GET /list -> {channel-ids: [INT..]}
|
||||||
# POST /allocate -> {channel-id: INT}
|
# POST /allocate -> {channel-id: INT}
|
||||||
# these return all messages for CHANNEL-ID= and MSGNUM= but SIDE!= :
|
# these return all messages for CHANNEL-ID= and MSGNUM= but SIDE!= :
|
||||||
# POST /CHANNEL-ID/SIDE/post/MSGNUM {message: STR} -> {messages: [STR..]}
|
# POST /CHANNEL-ID/SIDE/post/MSGNUM {message: STR} -> {messages: [STR..]}
|
||||||
# POST /CHANNEL-ID/SIDE/poll/MSGNUM -> {messages: [STR..]}
|
# POST /CHANNEL-ID/SIDE/poll/MSGNUM -> {messages: [STR..]}
|
||||||
# GET /CHANNEL-ID/SIDE/poll/MSGNUM (eventsource) -> STR, STR, ..
|
# GET /CHANNEL-ID/SIDE/poll/MSGNUM (eventsource) -> STR, STR, ..
|
||||||
#
|
|
||||||
# POST /CHANNEL-ID/SIDE/deallocate -> waiting | deleted
|
# POST /CHANNEL-ID/SIDE/deallocate -> waiting | deleted
|
||||||
|
|
||||||
class Channel(resource.Resource):
|
class Channel(resource.Resource):
|
||||||
|
@ -166,7 +165,6 @@ class Relay(resource.Resource):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
resource.Resource.__init__(self)
|
resource.Resource.__init__(self)
|
||||||
self.channels = {}
|
self.channels = {}
|
||||||
self.next_channel = 1
|
|
||||||
|
|
||||||
def prune_old_channels(self):
|
def prune_old_channels(self):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
@ -176,14 +174,26 @@ class Relay(resource.Resource):
|
||||||
log.msg("expiring %d" % channel_id)
|
log.msg("expiring %d" % channel_id)
|
||||||
self.free_child(channel_id)
|
self.free_child(channel_id)
|
||||||
|
|
||||||
|
def allocate_channel_id(self):
|
||||||
|
for size in range(1,4): # stick to 1-999 for now
|
||||||
|
available = set()
|
||||||
|
for cid in range(10**(size-1), 10**size):
|
||||||
|
if cid not in self.channels:
|
||||||
|
available.add(cid)
|
||||||
|
if available:
|
||||||
|
return random.choice(list(available))
|
||||||
|
# ouch, 999 currently allocated. Try random ones for a while.
|
||||||
|
for tries in range(1000):
|
||||||
|
cid = random.randrange(1000, 1000*1000)
|
||||||
|
if cid not in self.channels:
|
||||||
|
return cid
|
||||||
|
raise ValueError("unable to find a free channel-id")
|
||||||
|
|
||||||
def getChild(self, path, request):
|
def getChild(self, path, request):
|
||||||
if path == "allocate":
|
if path == "allocate":
|
||||||
# be more clever later. Rotate through 1-99 unless they're all
|
channel_id = self.allocate_channel_id()
|
||||||
# full, then rotate through 1-999, etc.
|
|
||||||
channel_id = self.next_channel
|
|
||||||
self.next_channel += 1
|
|
||||||
self.channels[channel_id] = Channel(channel_id, self)
|
self.channels[channel_id] = Channel(channel_id, self)
|
||||||
log.msg("allocated %d, now have %d channels" %
|
log.msg("allocated #%d, now have %d channels" %
|
||||||
(channel_id, len(self.channels)))
|
(channel_id, len(self.channels)))
|
||||||
return Allocated(channel_id)
|
return Allocated(channel_id)
|
||||||
if path == "list":
|
if path == "list":
|
||||||
|
@ -202,10 +212,8 @@ class Relay(resource.Resource):
|
||||||
|
|
||||||
def free_child(self, channel_id):
|
def free_child(self, channel_id):
|
||||||
self.channels.pop(channel_id)
|
self.channels.pop(channel_id)
|
||||||
log.msg("freed %d, now have %d channels" %
|
log.msg("freed #%d, now have %d channels" %
|
||||||
(channel_id, len(self.channels)))
|
(channel_id, len(self.channels)))
|
||||||
if not self.channels:
|
|
||||||
self.next_channel = 1
|
|
||||||
|
|
||||||
class TransitConnection(protocol.Protocol):
|
class TransitConnection(protocol.Protocol):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user