|
|
Descriptionmime/multipart: delay reading random source
If a user sets his/her own boundary string with SetBoundary,
we don't need to call randomBoundary at all.
Patch Set 1 #Patch Set 2 : diff -r 9eacb9c0d810 https://code.google.com/p/go #Patch Set 3 : diff -r 6146799f32ed https://code.google.com/p/go #Patch Set 4 : diff -r c860a8702b1b https://code.google.com/p/go #
MessagesTotal messages: 6
Hello golang-codereviews@googlegroups.com, I'd like you to review this change to https://code.google.com/p/go
Sign in to reply to this message.
LGTM
Sign in to reply to this message.
*** Submitted as https://code.google.com/p/go/source/detail?r=b2131d729e52 *** mime/multipart: delay reading random source If a user sets his/her own boundary string with SetBoundary, we don't need to call randomBoundary at all. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://codereview.appspot.com/95760043
Sign in to reply to this message.
This broke Camlistore. We didn't believe it at first and thought our continuous build (which tests both Go release & Go tip) was broken, but two of us have now independently confirmed that tests pass immediately before this change and reliably fail with this change. The server reports errors like: 2014/08/05 11:05:58 Client error: Error reading multipart section: multipart: NextPart: EOF I haven't identified exactly why yet, though. The change still looks safe to my eyes. On Tue, Jul 29, 2014 at 6:24 PM, <ruiu@google.com> wrote: > *** Submitted as > https://code.google.com/p/go/source/detail?r=b2131d729e52 *** > > mime/multipart: delay reading random source > > If a user sets his/her own boundary string with SetBoundary, > we don't need to call randomBoundary at all. > > LGTM=bradfitz > R=golang-codereviews, bradfitz > CC=golang-codereviews > https://codereview.appspot.com/95760043 > > > https://codereview.appspot.com/95760043/ >
Sign in to reply to this message.
I see. It's a data race.
Camlistore does:
pipeReader, pipeWriter := io.Pipe()
multipartWriter := *multipart.NewWriter*(pipeWriter)
copyResult := make(chan error, 1)
go func() {
defer pipeWriter.Close()
part, err := *multipartWriter.CreateFormFile*(blobrefStr,
blobrefStr)
if err != nil {
copyResult <- err
return
}
_, err = io.Copy(part, bodyReader)
if err == nil {
err = multipartWriter.Close()
}
copyResult <- err
}()
uploadURL := fmt.Sprintf("%s/camli/upload", pfx)
req := c.newRequest("POST", uploadURL)
req.Header.Set("Content-Type", *multipartWriter.FormDataContentType*
())
==================
WARNING: DATA RACE
Read by goroutine 32:
mime/multipart.(*Writer).Boundary()
/Users/bradfitz/go/src/pkg/mime/multipart/writer.go:34 +0x4c
mime/multipart.(*Writer).CreatePart()
/Users/bradfitz/go/src/pkg/mime/multipart/writer.go:96 +0x975
mime/multipart.(*Writer).CreateFormFile()
/Users/bradfitz/go/src/pkg/mime/multipart/writer.go:131 +0x27e
camlistore.org/pkg/client.func·013()
<http://camlistore.org/pkg/client.func%C2%B7013()>
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:436
+0xe6
Previous write by goroutine 31:
mime/multipart.(*Writer).Boundary()
/Users/bradfitz/go/src/pkg/mime/multipart/writer.go:35 +0x86
mime/multipart.(*Writer).FormDataContentType()
/Users/bradfitz/go/src/pkg/mime/multipart/writer.go:70 +0x46
camlistore.org/pkg/client.(*Client).Upload()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:453
+0x1ac5
camlistore.org/pkg/client.(*Client).ReceiveBlob()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/get.go:177
+0x2bc
main.(*noStatReceiver).ReceiveBlob()
<autogenerated>:166 +0xd1
camlistore.org/pkg/blobserver.receive()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:50
+0x2b8
camlistore.org/pkg/blobserver.ReceiveNoHash()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:42
+0xaf
camlistore.org/pkg/schema.uploadString()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:197
+0x30e
camlistore.org/pkg/schema.func·008()
<http://camlistore.org/pkg/schema.func%C2%B7008()>
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:367
+0xf5
Goroutine 32 (running) created at:
camlistore.org/pkg/client.(*Client).Upload()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:446
+0x1958
camlistore.org/pkg/client.(*Client).ReceiveBlob()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/get.go:177
+0x2bc
main.(*noStatReceiver).ReceiveBlob()
<autogenerated>:166 +0xd1
camlistore.org/pkg/blobserver.receive()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:50
+0x2b8
camlistore.org/pkg/blobserver.ReceiveNoHash()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:42
+0xaf
camlistore.org/pkg/schema.uploadString()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:197
+0x30e
camlistore.org/pkg/schema.func·008()
<http://camlistore.org/pkg/schema.func%C2%B7008()>
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:367
+0xf5
Goroutine 31 (running) created at:
camlistore.org/pkg/schema.func·009()
<http://camlistore.org/pkg/schema.func%C2%B7009()>
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:373
+0x437
camlistore.org/pkg/schema.writeFileChunks()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:382
+0x6ca
camlistore.org/pkg/schema.writeFileMapRolling()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:312
+0xa1
camlistore.org/pkg/schema.WriteFileMap()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:78
+0x90
main.(*Uploader).uploadNodeRegularFile()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:631
+0x13ad
main.(*Uploader).uploadNode()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:381
+0xc7
main.func·018()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:1040
+0x1a9
main.(*nodeWorker).work()
/Users/bradfitz/src/
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/chanworker.go:116
+0x115
==================
On Tue, Aug 5, 2014 at 11:12 AM, Brad Fitzpatrick <bradfitz@golang.org>
wrote:
> This broke Camlistore.
>
> We didn't believe it at first and thought our continuous build (which
> tests both Go release & Go tip) was broken, but two of us have now
> independently confirmed that tests pass immediately before this change and
> reliably fail with this change.
>
> The server reports errors like:
> 2014/08/05 11:05:58 Client error: Error reading multipart section:
> multipart: NextPart: EOF
>
> I haven't identified exactly why yet, though. The change still looks safe
> to my eyes.
>
>
>
>
> On Tue, Jul 29, 2014 at 6:24 PM, <ruiu@google.com> wrote:
>
>> *** Submitted as
>> https://code.google.com/p/go/source/detail?r=b2131d729e52 ***
>>
>> mime/multipart: delay reading random source
>>
>> If a user sets his/her own boundary string with SetBoundary,
>> we don't need to call randomBoundary at all.
>>
>> LGTM=bradfitz
>> R=golang-codereviews, bradfitz
>> CC=golang-codereviews
>> https://codereview.appspot.com/95760043
>>
>>
>> https://codereview.appspot.com/95760043/
>>
>
>
Sign in to reply to this message.
Message was sent while issue was closed.
On 2014/08/05 18:24:04, bradfitz wrote:
> I see. It's a data race.
>
> Camlistore does:
>
> pipeReader, pipeWriter := io.Pipe()
> multipartWriter := *multipart.NewWriter*(pipeWriter)
>
> copyResult := make(chan error, 1)
> go func() {
> defer pipeWriter.Close()
> part, err := *multipartWriter.CreateFormFile*(blobrefStr,
> blobrefStr)
> if err != nil {
> copyResult <- err
> return
> }
> _, err = io.Copy(part, bodyReader)
> if err == nil {
> err = multipartWriter.Close()
> }
> copyResult <- err
> }()
>
> uploadURL := fmt.Sprintf("%s/camli/upload", pfx)
> req := c.newRequest("POST", uploadURL)
> req.Header.Set("Content-Type", *multipartWriter.FormDataContentType*
> ())
>
> ==================
> WARNING: DATA RACE
> Read by goroutine 32:
> mime/multipart.(*Writer).Boundary()
> /Users/bradfitz/go/src/pkg/mime/multipart/writer.go:34 +0x4c
> mime/multipart.(*Writer).CreatePart()
> /Users/bradfitz/go/src/pkg/mime/multipart/writer.go:96 +0x975
> mime/multipart.(*Writer).CreateFormFile()
> /Users/bradfitz/go/src/pkg/mime/multipart/writer.go:131 +0x27e
> camlistore.org/pkg/client.func·013()
> <http://camlistore.org/pkg/client.func%C2%B7013()>
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:436
> +0xe6
>
> Previous write by goroutine 31:
> mime/multipart.(*Writer).Boundary()
> /Users/bradfitz/go/src/pkg/mime/multipart/writer.go:35 +0x86
> mime/multipart.(*Writer).FormDataContentType()
> /Users/bradfitz/go/src/pkg/mime/multipart/writer.go:70 +0x46
> camlistore.org/pkg/client.(*Client).Upload()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:453
> +0x1ac5
> camlistore.org/pkg/client.(*Client).ReceiveBlob()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/get.go:177
> +0x2bc
> main.(*noStatReceiver).ReceiveBlob()
> <autogenerated>:166 +0xd1
> camlistore.org/pkg/blobserver.receive()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:50
> +0x2b8
> camlistore.org/pkg/blobserver.ReceiveNoHash()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:42
> +0xaf
> camlistore.org/pkg/schema.uploadString()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:197
> +0x30e
> camlistore.org/pkg/schema.func·008()
> <http://camlistore.org/pkg/schema.func%C2%B7008()>
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:367
> +0xf5
>
> Goroutine 32 (running) created at:
> camlistore.org/pkg/client.(*Client).Upload()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/upload.go:446
> +0x1958
> camlistore.org/pkg/client.(*Client).ReceiveBlob()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/client/get.go:177
> +0x2bc
> main.(*noStatReceiver).ReceiveBlob()
> <autogenerated>:166 +0xd1
> camlistore.org/pkg/blobserver.receive()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:50
> +0x2b8
> camlistore.org/pkg/blobserver.ReceiveNoHash()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/blobserver/receive.go:42
> +0xaf
> camlistore.org/pkg/schema.uploadString()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:197
> +0x30e
> camlistore.org/pkg/schema.func·008()
> <http://camlistore.org/pkg/schema.func%C2%B7008()>
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:367
> +0xf5
>
> Goroutine 31 (running) created at:
> camlistore.org/pkg/schema.func·009()
> <http://camlistore.org/pkg/schema.func%C2%B7009()>
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:373
> +0x437
> camlistore.org/pkg/schema.writeFileChunks()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:382
> +0x6ca
> camlistore.org/pkg/schema.writeFileMapRolling()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:312
> +0xa1
> camlistore.org/pkg/schema.WriteFileMap()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/pkg/schema/filewriter.go:78
> +0x90
> main.(*Uploader).uploadNodeRegularFile()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:631
> +0x13ad
> main.(*Uploader).uploadNode()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:381
> +0xc7
> main.func·018()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/files.go:1040
> +0x1a9
> main.(*nodeWorker).work()
> /Users/bradfitz/src/
>
camlistore.org/tmp/build-gopath-nosqlite/src/camlistore.org/cmd/camput/chanworker.go:116
> +0x115
> ==================
>
>
> On Tue, Aug 5, 2014 at 11:12 AM, Brad Fitzpatrick <mailto:bradfitz@golang.org>
> wrote:
>
> > This broke Camlistore.
> >
> > We didn't believe it at first and thought our continuous build (which
> > tests both Go release & Go tip) was broken, but two of us have now
> > independently confirmed that tests pass immediately before this change and
> > reliably fail with this change.
> >
> > The server reports errors like:
> > 2014/08/05 11:05:58 Client error: Error reading multipart section:
> > multipart: NextPart: EOF
> >
> > I haven't identified exactly why yet, though. The change still looks safe
> > to my eyes.
> >
> >
> >
> >
> > On Tue, Jul 29, 2014 at 6:24 PM, <mailto:ruiu@google.com> wrote:
> >
> >> *** Submitted as
> >> https://code.google.com/p/go/source/detail?r=b2131d729e52 ***
> >>
> >> mime/multipart: delay reading random source
> >>
> >> If a user sets his/her own boundary string with SetBoundary,
> >> we don't need to call randomBoundary at all.
> >>
> >> LGTM=bradfitz
> >> R=golang-codereviews, bradfitz
> >> CC=golang-codereviews
> >> https://codereview.appspot.com/95760043
> >>
> >>
> >> https://codereview.appspot.com/95760043/
> >>
> >
> >
Can we have this as a test in std lib? We have so few good concurrent tests...
Sign in to reply to this message.
|
|||||||||||||||||||||||||||||||||||||||||||
