[tahoe-lafs-trac-stream] [Tahoe-LAFS] #541: remove foolscap 'reference'-token bug workaround in mutable publish (was: foolscap 'reference'-token bug workaround in mutable publish)

Tahoe-LAFS trac at tahoe-lafs.org
Tue Aug 25 17:41:44 UTC 2015


#541: remove foolscap 'reference'-token bug workaround in mutable publish
-----------------------------+---------------------------------------------
     Reporter:  warner       |      Owner:
         Type:  defect       |     Status:  new
     Priority:  major        |  Milestone:  1.12.0
    Component:  code-        |    Version:  1.2.0
  mutable                    |   Keywords:  backward-compatibility foolscap
   Resolution:               |
Launchpad Bug:               |
-----------------------------+---------------------------------------------
Description changed by zooko:

Old description:

> Foolscap 0.2.5 had a bug in which an inbound constraint (say
> a{{{TupleConstraint}}}) wouldn't accept a 'reference' token that pointed
> at a tuple. This would occur when the same tuple was sent multiple times
> in a single request.
>
> The mutable-file publish code, when it is creating a brand-new mutable
> file, and when there are fewer than N servers (so multiple shares are
> sent to the same server), can trigger this case, because the same assert-
> that-there-are-no-shares test vector (a static tuple of numbers and
> strings) is used once per share. Python seems to compile the tuple once,
> so foolscap sees the same object appear in the outbound arguments
> multiple times, and uses the 'reference' token to preserve this
> (unintentional) relationship.
>
> The workaround is to construct this tuple at runtime, basically changing:
>
> {{{
>  for x in something:
>    testv = (0, 1, 'eq', '')
>    stuff.append(testv)
> }}}
>
> into:
>
> {{{
>  for x in something:
>    testv = tuple([0, 1, 'eq', ''])
>    stuff.append(testv)
> }}}
>
> The constraint bug was fixed in foolscap-0.2.6, but since it's an
> inbound-side bug, what really matters is the version of foolscap on the
> other end of the wire, so to interoperate with older versions of tahoe
> (which may be using older versions of foolscap), we must avoid sending
> the 'reference' token at all. So this workaround (which was removed in
> [changeset:f7b4c45d4651b25b] because tahoe now requires a newer version
> of foolscap) needs to be reinstated.
>
> In addition, I've seen another problem that relates to this code. A few
> days ago I started noticing failures in the buildbot 'speed test', which
> runs trunk code against a statically configured 'perfnet' (with a client
> node on prodcs2 and four storage nodes plus introducer on tahoebs1). Four
> nodes and ten shares means multiple shares per node, so the testv-and-
> readv-and-writev call gets multiple shares, which means a 'reference'
> token.
>
> The storage server appears to still have problems with the 'reference'
> token, even though it's running foolscap-0.3.1 . Sometimes I see a
> Violation that claims getObject(reftoken) returned a non-tuple. Sometimes
> I see a "dangling reference" !BananaError, which indicates that
> getObject() failed to find the reference. The !BananaError causes the
> connection to be dropped, so any remaining writev calls fail with a
> !DeadReferenceError.
>
> I can provoke this behavior with a local trunk tree against the storage
> nodes on tahoebs1. I haven't been able to reproduce this with local
> storage nodes (running foolscap-0.3.1). If I reintroduce the
> {{{tuple([0,1,'eq',''])}}} workaround, the problem seems to go away.
>
> If I revert the recent versioning changes (which tries to call
> 'get_version' on the storage server, and falls back to a default value if
> that fails), then the problem seems to go away. The tahoebs1 perfnet
> nodes are a few months old (they are running r2901), so they don't have
> {{{get_version()}}}. So I'm suspecting that the Violation that gets
> raised somehow messes things up, such that getObject() remembers some bit
> of bogus state, so later getObject() calls either get a bad value or no
> value at all.
>
> I'm going to commit the {{{tuple([0,1,'eq',''])}}} workaround, since we
> need it anyways. But at some point we need to come back to this and
> examine it further, because I still don't understand the new problem.
>
> The first step will be to add instrumentation to the storage servers,
> which means first bouncing one of the tahoebs1 nodes and see if it still
> has the problem. (running the same code locally didn't experience the
> problem; the only difference I can think of is that the tahoebs1 nodes
> have been running for two months, and might have all experienced
> something in that time to mess them up now, whereas my local nodes are
> younger).

New description:

 To close this ticket, remove the workaround which was needed only to avoid
 a Foolscap bug which is long since fixed.

 ------- old description:

 Foolscap 0.2.5 had a bug in which an inbound constraint (say
 a{{{TupleConstraint}}}) wouldn't accept a 'reference' token that pointed
 at a tuple. This would occur when the same tuple was sent multiple times
 in a single request.

 The mutable-file publish code, when it is creating a brand-new mutable
 file, and when there are fewer than N servers (so multiple shares are sent
 to the same server), can trigger this case, because the same assert-that-
 there-are-no-shares test vector (a static tuple of numbers and strings) is
 used once per share. Python seems to compile the tuple once, so foolscap
 sees the same object appear in the outbound arguments multiple times, and
 uses the 'reference' token to preserve this (unintentional) relationship.

 The workaround is to construct this tuple at runtime, basically changing:

 {{{
  for x in something:
    testv = (0, 1, 'eq', '')
    stuff.append(testv)
 }}}

 into:

 {{{
  for x in something:
    testv = tuple([0, 1, 'eq', ''])
    stuff.append(testv)
 }}}

 The constraint bug was fixed in foolscap-0.2.6, but since it's an inbound-
 side bug, what really matters is the version of foolscap on the other end
 of the wire, so to interoperate with older versions of tahoe (which may be
 using older versions of foolscap), we must avoid sending the 'reference'
 token at all. So this workaround (which was removed in
 [changeset:f7b4c45d4651b25b] because tahoe now requires a newer version of
 foolscap) needs to be reinstated.

 In addition, I've seen another problem that relates to this code. A few
 days ago I started noticing failures in the buildbot 'speed test', which
 runs trunk code against a statically configured 'perfnet' (with a client
 node on prodcs2 and four storage nodes plus introducer on tahoebs1). Four
 nodes and ten shares means multiple shares per node, so the testv-and-
 readv-and-writev call gets multiple shares, which means a 'reference'
 token.

 The storage server appears to still have problems with the 'reference'
 token, even though it's running foolscap-0.3.1 . Sometimes I see a
 Violation that claims getObject(reftoken) returned a non-tuple. Sometimes
 I see a "dangling reference" !BananaError, which indicates that
 getObject() failed to find the reference. The !BananaError causes the
 connection to be dropped, so any remaining writev calls fail with a
 !DeadReferenceError.

 I can provoke this behavior with a local trunk tree against the storage
 nodes on tahoebs1. I haven't been able to reproduce this with local
 storage nodes (running foolscap-0.3.1). If I reintroduce the
 {{{tuple([0,1,'eq',''])}}} workaround, the problem seems to go away.

 If I revert the recent versioning changes (which tries to call
 'get_version' on the storage server, and falls back to a default value if
 that fails), then the problem seems to go away. The tahoebs1 perfnet nodes
 are a few months old (they are running r2901), so they don't have
 {{{get_version()}}}. So I'm suspecting that the Violation that gets raised
 somehow messes things up, such that getObject() remembers some bit of
 bogus state, so later getObject() calls either get a bad value or no value
 at all.

 I'm going to commit the {{{tuple([0,1,'eq',''])}}} workaround, since we
 need it anyways. But at some point we need to come back to this and
 examine it further, because I still don't understand the new problem.

 The first step will be to add instrumentation to the storage servers,
 which means first bouncing one of the tahoebs1 nodes and see if it still
 has the problem. (running the same code locally didn't experience the
 problem; the only difference I can think of is that the tahoebs1 nodes
 have been running for two months, and might have all experienced something
 in that time to mess them up now, whereas my local nodes are younger).

--

--
Ticket URL: <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/541#comment:11>
Tahoe-LAFS <https://Tahoe-LAFS.org>
secure decentralized storage


More information about the tahoe-lafs-trac-stream mailing list