12715: Fix slow PROPFIND by avoiding content probing.
authorTom Clegg <tclegg@veritasgenetics.com>
Fri, 15 Dec 2017 03:25:38 +0000 (22:25 -0500)
committerTom Clegg <tclegg@veritasgenetics.com>
Fri, 15 Dec 2017 03:29:57 +0000 (22:29 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg@veritasgenetics.com>

services/keep-web/handler.go
services/keep-web/webdav.go

index a1476d3a8eb1b62fad8ea519702ec290e7f3472c..4cb2fdba821e8bca5f8b635390d9bf9a6cae556a 100644 (file)
@@ -443,6 +443,7 @@ func (h *handler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) {
                        FileSystem: &webdavFS{
                                collfs:  fs,
                                writing: writeMethod[r.Method],
+                               reading: r.Method != "PROPFIND",
                        },
                        LockSystem: h.webdavLS,
                        Logger: func(_ *http.Request, err error) {
index 3ceb0ed5c9ea6c71f06e5ad857ad1223bb277433..98e6f01987b5de971e005eb1d471b82a5615d3ac 100644 (file)
@@ -8,6 +8,7 @@ import (
        "crypto/rand"
        "errors"
        "fmt"
+       "io"
        prand "math/rand"
        "os"
        "path"
@@ -37,6 +38,7 @@ var (
 type webdavFS struct {
        collfs  arvados.CollectionFileSystem
        writing bool
+       reading bool
 }
 
 func (fs *webdavFS) makeparents(name string) {
@@ -71,6 +73,15 @@ func (fs *webdavFS) OpenFile(ctx context.Context, name string, flag int, perm os
                // have 405.
                f = writeFailer{File: f, err: errReadOnly}
        }
+       if !fs.reading {
+               // webdav PROPFIND reads the first few bytes of each
+               // file whose filename extension isn't recognized,
+               // which is prohibitively expensive: we end up
+               // fetching multiple 64MiB blocks. Avoid this by
+               // returning EOF on all reads when handling a
+               // PROPFIND.
+               f = readEOF{File: f}
+       }
        return
 }
 
@@ -106,6 +117,14 @@ func (wf writeFailer) Close() error {
        return wf.err
 }
 
+type readEOF struct {
+       webdav.File
+}
+
+func (readEOF) Read(p []byte) (int, error) {
+       return 0, io.EOF
+}
+
 // noLockSystem implements webdav.LockSystem by returning success for
 // every possible locking operation, even though it has no side
 // effects such as actually locking anything. This works for a