mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 05:28:04 +00:00
webish.py: fix for #237: when listing large directories, insert a turn break once every 100 children, to work around non-optimized tail recursion Deferreds
This commit is contained in:
parent
e400c5a8fb
commit
124b2160b9
@ -18,6 +18,7 @@ from allmydata import get_package_versions_string
|
|||||||
from zope.interface import implements, Interface
|
from zope.interface import implements, Interface
|
||||||
import urllib
|
import urllib
|
||||||
from formless import webform
|
from formless import webform
|
||||||
|
from foolscap.eventual import fireEventually
|
||||||
|
|
||||||
from nevow.util import resource_filename
|
from nevow.util import resource_filename
|
||||||
|
|
||||||
@ -209,6 +210,25 @@ class Directory(rend.Page):
|
|||||||
def data_children(self, ctx, data):
|
def data_children(self, ctx, data):
|
||||||
d = self._dirnode.list()
|
d = self._dirnode.list()
|
||||||
d.addCallback(lambda dict: sorted(dict.items()))
|
d.addCallback(lambda dict: sorted(dict.items()))
|
||||||
|
def _stall_some(items):
|
||||||
|
# Deferreds don't optimize out tail recursion, and the way
|
||||||
|
# Nevow's flattener handles Deferreds doesn't take this into
|
||||||
|
# account. As a result, large lists of Deferreds that fire in the
|
||||||
|
# same turn (i.e. the output of defer.succeed) will cause a stack
|
||||||
|
# overflow. To work around this, we insert a turn break after
|
||||||
|
# every 100 items, using foolscap's fireEventually(). This gives
|
||||||
|
# the stack a chance to be popped. It would also work to put
|
||||||
|
# every item in its own turn, but that'd be a lot more
|
||||||
|
# inefficient. This addresses ticket #237, for which I was never
|
||||||
|
# able to create a failing unit test.
|
||||||
|
output = []
|
||||||
|
for i,item in enumerate(items):
|
||||||
|
if i % 100 == 0:
|
||||||
|
output.append(fireEventually(item))
|
||||||
|
else:
|
||||||
|
output.append(item)
|
||||||
|
return output
|
||||||
|
d.addCallback(_stall_some)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def render_row(self, ctx, data):
|
def render_row(self, ctx, data):
|
||||||
|
Loading…
Reference in New Issue
Block a user