diff --git a/cmd/lock-rest-client.go b/cmd/lock-rest-client.go
index 12a8664d2..44e709db7 100644
--- a/cmd/lock-rest-client.go
+++ b/cmd/lock-rest-client.go
@@ -22,7 +22,6 @@ import (
"context"
"io"
"net/url"
- "strconv"
"github.com/minio/minio/internal/dsync"
"github.com/minio/minio/internal/http"
@@ -89,17 +88,13 @@ func (client *lockRESTClient) Close() error {
// restCall makes a call to the lock REST server.
func (client *lockRESTClient) restCall(ctx context.Context, call string, args dsync.LockArgs) (reply bool, err error) {
- values := url.Values{}
- values.Set(lockRESTUID, args.UID)
- values.Set(lockRESTOwner, args.Owner)
- values.Set(lockRESTSource, args.Source)
- values.Set(lockRESTQuorum, strconv.Itoa(args.Quorum))
- var buffer bytes.Buffer
- for _, resource := range args.Resources {
- buffer.WriteString(resource)
- buffer.WriteString("\n")
+ argsBytes, err := args.MarshalMsg(metaDataPoolGet()[:0])
+ if err != nil {
+ return false, err
}
- respBody, err := client.callWithContext(ctx, call, values, &buffer, -1)
+ defer metaDataPoolPut(argsBytes)
+ body := bytes.NewReader(argsBytes)
+ respBody, err := client.callWithContext(ctx, call, nil, body, body.Size())
defer http.DrainBody(respBody)
switch err {
case nil:
diff --git a/cmd/lock-rest-server-common.go b/cmd/lock-rest-server-common.go
index 2964671f0..dfc1938aa 100644
--- a/cmd/lock-rest-server-common.go
+++ b/cmd/lock-rest-server-common.go
@@ -22,7 +22,7 @@ import (
)
const (
- lockRESTVersion = "v6" // Add Refresh API
+ lockRESTVersion = "v7" // Add msgp for lockArgs
lockRESTVersionPrefix = SlashSeparator + lockRESTVersion
lockRESTPrefix = minioReservedBucketPath + "/lock"
)
@@ -35,20 +35,6 @@ const (
lockRESTMethodUnlock = "/unlock"
lockRESTMethodRUnlock = "/runlock"
lockRESTMethodForceUnlock = "/force-unlock"
-
- // lockRESTOwner represents owner UUID
- lockRESTOwner = "owner"
-
- // Unique ID of lock/unlock request.
- lockRESTUID = "uid"
-
- // Source contains the line number, function and file name of the code
- // on the client node that requested the lock.
- lockRESTSource = "source"
-
- // Quroum value to be saved along lock requester info, useful
- // in verifying stale locks
- lockRESTQuorum = "quorum"
)
var (
diff --git a/cmd/lock-rest-server.go b/cmd/lock-rest-server.go
index bebd00ca4..88f832413 100644
--- a/cmd/lock-rest-server.go
+++ b/cmd/lock-rest-server.go
@@ -18,14 +18,13 @@
package cmd
import (
- "bufio"
"context"
"errors"
+ "io"
"net/http"
- "sort"
- "strconv"
"time"
+ "github.com/dustin/go-humanize"
"github.com/gorilla/mux"
"github.com/minio/minio/internal/dsync"
)
@@ -63,32 +62,10 @@ func (l *lockRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool {
}
func getLockArgs(r *http.Request) (args dsync.LockArgs, err error) {
- values := r.Form
- quorum, err := strconv.Atoi(values.Get(lockRESTQuorum))
- if err != nil {
- return args, err
- }
-
- args = dsync.LockArgs{
- Owner: values.Get(lockRESTOwner),
- UID: values.Get(lockRESTUID),
- Source: values.Get(lockRESTSource),
- Quorum: quorum,
- }
-
- var resources []string
- bio := bufio.NewScanner(r.Body)
- for bio.Scan() {
- resources = append(resources, bio.Text())
- }
-
- if err := bio.Err(); err != nil {
- return args, err
- }
-
- sort.Strings(resources)
- args.Resources = resources
- return args, nil
+ dec := msgpNewReader(io.LimitReader(r.Body, 1000*humanize.KiByte))
+ defer readMsgpReaderPool.Put(dec)
+ err = args.DecodeMsg(dec)
+ return args, err
}
// HealthHandler returns success if request is authenticated.
diff --git a/cmd/lock-rest-server_test.go b/cmd/lock-rest-server_test.go
new file mode 100644
index 000000000..1a8fee8c4
--- /dev/null
+++ b/cmd/lock-rest-server_test.go
@@ -0,0 +1,104 @@
+// Copyright (c) 2015-2021 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "bufio"
+ "bytes"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "sort"
+ "strconv"
+ "testing"
+
+ "github.com/minio/minio/internal/dsync"
+)
+
+func BenchmarkLockArgs(b *testing.B) {
+ args := dsync.LockArgs{
+ Owner: "minio",
+ UID: "uid",
+ Source: "lockArgs.go",
+ Quorum: 3,
+ Resources: []string{"obj.txt"},
+ }
+
+ argBytes, err := args.MarshalMsg(nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ req := &http.Request{
+ Body: ioutil.NopCloser(bytes.NewReader(argBytes)),
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ getLockArgs(req)
+ }
+}
+
+func BenchmarkLockArgsOld(b *testing.B) {
+ values := url.Values{}
+ values.Set("owner", "minio")
+ values.Set("uid", "uid")
+ values.Set("source", "lockArgs.go")
+ values.Set("quorum", "3")
+
+ req := &http.Request{
+ Form: values,
+ Body: ioutil.NopCloser(bytes.NewReader([]byte(`obj.txt`))),
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ getLockArgsOld(req)
+ }
+}
+
+func getLockArgsOld(r *http.Request) (args dsync.LockArgs, err error) {
+ values := r.Form
+ quorum, err := strconv.Atoi(values.Get("quorum"))
+ if err != nil {
+ return args, err
+ }
+
+ args = dsync.LockArgs{
+ Owner: values.Get("onwer"),
+ UID: values.Get("uid"),
+ Source: values.Get("source"),
+ Quorum: quorum,
+ }
+
+ var resources []string
+ bio := bufio.NewScanner(r.Body)
+ for bio.Scan() {
+ resources = append(resources, bio.Text())
+ }
+
+ if err := bio.Err(); err != nil {
+ return args, err
+ }
+
+ sort.Strings(resources)
+ args.Resources = resources
+ return args, nil
+}
diff --git a/cmd/storage-errors.go b/cmd/storage-errors.go
index f310e87ef..070e7848a 100644
--- a/cmd/storage-errors.go
+++ b/cmd/storage-errors.go
@@ -157,7 +157,10 @@ func osErrToFileErr(err error) error {
return errFaultyDisk
}
if isSysErrInvalidArg(err) {
- return errUnsupportedDisk
+ // For some odd calls with O_DIRECT reads
+ // filesystems can return EINVAL, handle
+ // these as FileNotFound instead.
+ return errFileNotFound
}
if isSysErrNoSpace(err) {
return errDiskFull
diff --git a/internal/dsync/drwmutex.go b/internal/dsync/drwmutex.go
index 1ab507846..dfb438477 100644
--- a/internal/dsync/drwmutex.go
+++ b/internal/dsync/drwmutex.go
@@ -22,6 +22,7 @@ import (
"errors"
"math/rand"
"os"
+ "sort"
"sync"
"time"
@@ -86,6 +87,7 @@ func isLocked(uid string) bool {
// NewDRWMutex - initializes a new dsync RW mutex.
func NewDRWMutex(clnt *Dsync, names ...string) *DRWMutex {
restClnts, _ := clnt.GetLockers()
+ sort.Strings(names)
return &DRWMutex{
writeLocks: make([]string, len(restClnts)),
Names: names,
@@ -372,7 +374,7 @@ func refresh(ctx context.Context, ds *Dsync, id, source string, quorum int) (boo
}
// lock tries to acquire the distributed lock, returning true or false.
-func lock(ctx context.Context, ds *Dsync, locks *[]string, id, source string, isReadLock bool, tolerance, quorum int, lockNames ...string) bool {
+func lock(ctx context.Context, ds *Dsync, locks *[]string, id, source string, isReadLock bool, tolerance, quorum int, names ...string) bool {
for i := range *locks {
(*locks)[i] = ""
}
@@ -386,7 +388,7 @@ func lock(ctx context.Context, ds *Dsync, locks *[]string, id, source string, is
args := LockArgs{
Owner: owner,
UID: id,
- Resources: lockNames,
+ Resources: names,
Source: source,
Quorum: quorum,
}
@@ -468,7 +470,7 @@ func lock(ctx context.Context, ds *Dsync, locks *[]string, id, source string, is
if !quorumLocked {
log("dsync: Unable to acquire lock in quorum %#v\n", args)
// Release all acquired locks without quorum.
- if !releaseAll(ds, tolerance, owner, locks, isReadLock, restClnts, lockNames...) {
+ if !releaseAll(ds, tolerance, owner, locks, isReadLock, restClnts, names...) {
log("Unable to release acquired locks, these locks will expire automatically %#v\n", args)
}
}
@@ -482,7 +484,7 @@ func lock(ctx context.Context, ds *Dsync, locks *[]string, id, source string, is
// release abandoned lock
log("Releasing abandoned lock\n")
sendRelease(ds, restClnts[grantToBeReleased.index],
- owner, grantToBeReleased.lockUID, isReadLock, lockNames...)
+ owner, grantToBeReleased.lockUID, isReadLock, names...)
}
}
}()
@@ -530,14 +532,14 @@ func checkQuorumLocked(locks *[]string, quorum int) bool {
}
// releaseAll releases all locks that are marked as locked
-func releaseAll(ds *Dsync, tolerance int, owner string, locks *[]string, isReadLock bool, restClnts []NetLocker, lockNames ...string) bool {
+func releaseAll(ds *Dsync, tolerance int, owner string, locks *[]string, isReadLock bool, restClnts []NetLocker, names ...string) bool {
var wg sync.WaitGroup
for lockID := range restClnts {
wg.Add(1)
go func(lockID int) {
defer wg.Done()
if isLocked((*locks)[lockID]) {
- if sendRelease(ds, restClnts[lockID], owner, (*locks)[lockID], isReadLock, lockNames...) {
+ if sendRelease(ds, restClnts[lockID], owner, (*locks)[lockID], isReadLock, names...) {
(*locks)[lockID] = ""
}
}
diff --git a/internal/dsync/lock-args.go b/internal/dsync/lock-args.go
new file mode 100644
index 000000000..66adead7f
--- /dev/null
+++ b/internal/dsync/lock-args.go
@@ -0,0 +1,40 @@
+// Copyright (c) 2015-2021 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package dsync
+
+//go:generate msgp -file $GOFILE
+
+// LockArgs is minimal required values for any dsync compatible lock operation.
+type LockArgs struct {
+ // Unique ID of lock/unlock request.
+ UID string
+
+ // Resources contains single or multiple entries to be locked/unlocked.
+ Resources []string
+
+ // Source contains the line number, function and file name of the code
+ // on the client node that requested the lock.
+ Source string
+
+ // Owner represents unique ID for this instance, an owner who originally requested
+ // the locked resource, useful primarily in figuring our stale locks.
+ Owner string
+
+ // Quorum represents the expected quorum for this lock type.
+ Quorum int
+}
diff --git a/internal/dsync/lock-args_gen.go b/internal/dsync/lock-args_gen.go
new file mode 100644
index 000000000..46bc4b475
--- /dev/null
+++ b/internal/dsync/lock-args_gen.go
@@ -0,0 +1,250 @@
+package dsync
+
+// Code generated by github.com/tinylib/msgp DO NOT EDIT.
+
+import (
+ "github.com/tinylib/msgp/msgp"
+)
+
+// DecodeMsg implements msgp.Decodable
+func (z *LockArgs) DecodeMsg(dc *msgp.Reader) (err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, err = dc.ReadMapHeader()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, err = dc.ReadMapKeyPtr()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "UID":
+ z.UID, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "UID")
+ return
+ }
+ case "Resources":
+ var zb0002 uint32
+ zb0002, err = dc.ReadArrayHeader()
+ if err != nil {
+ err = msgp.WrapError(err, "Resources")
+ return
+ }
+ if cap(z.Resources) >= int(zb0002) {
+ z.Resources = (z.Resources)[:zb0002]
+ } else {
+ z.Resources = make([]string, zb0002)
+ }
+ for za0001 := range z.Resources {
+ z.Resources[za0001], err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "Resources", za0001)
+ return
+ }
+ }
+ case "Source":
+ z.Source, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "Source")
+ return
+ }
+ case "Owner":
+ z.Owner, err = dc.ReadString()
+ if err != nil {
+ err = msgp.WrapError(err, "Owner")
+ return
+ }
+ case "Quorum":
+ z.Quorum, err = dc.ReadInt()
+ if err != nil {
+ err = msgp.WrapError(err, "Quorum")
+ return
+ }
+ default:
+ err = dc.Skip()
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ return
+}
+
+// EncodeMsg implements msgp.Encodable
+func (z *LockArgs) EncodeMsg(en *msgp.Writer) (err error) {
+ // map header, size 5
+ // write "UID"
+ err = en.Append(0x85, 0xa3, 0x55, 0x49, 0x44)
+ if err != nil {
+ return
+ }
+ err = en.WriteString(z.UID)
+ if err != nil {
+ err = msgp.WrapError(err, "UID")
+ return
+ }
+ // write "Resources"
+ err = en.Append(0xa9, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73)
+ if err != nil {
+ return
+ }
+ err = en.WriteArrayHeader(uint32(len(z.Resources)))
+ if err != nil {
+ err = msgp.WrapError(err, "Resources")
+ return
+ }
+ for za0001 := range z.Resources {
+ err = en.WriteString(z.Resources[za0001])
+ if err != nil {
+ err = msgp.WrapError(err, "Resources", za0001)
+ return
+ }
+ }
+ // write "Source"
+ err = en.Append(0xa6, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65)
+ if err != nil {
+ return
+ }
+ err = en.WriteString(z.Source)
+ if err != nil {
+ err = msgp.WrapError(err, "Source")
+ return
+ }
+ // write "Owner"
+ err = en.Append(0xa5, 0x4f, 0x77, 0x6e, 0x65, 0x72)
+ if err != nil {
+ return
+ }
+ err = en.WriteString(z.Owner)
+ if err != nil {
+ err = msgp.WrapError(err, "Owner")
+ return
+ }
+ // write "Quorum"
+ err = en.Append(0xa6, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d)
+ if err != nil {
+ return
+ }
+ err = en.WriteInt(z.Quorum)
+ if err != nil {
+ err = msgp.WrapError(err, "Quorum")
+ return
+ }
+ return
+}
+
+// MarshalMsg implements msgp.Marshaler
+func (z *LockArgs) MarshalMsg(b []byte) (o []byte, err error) {
+ o = msgp.Require(b, z.Msgsize())
+ // map header, size 5
+ // string "UID"
+ o = append(o, 0x85, 0xa3, 0x55, 0x49, 0x44)
+ o = msgp.AppendString(o, z.UID)
+ // string "Resources"
+ o = append(o, 0xa9, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73)
+ o = msgp.AppendArrayHeader(o, uint32(len(z.Resources)))
+ for za0001 := range z.Resources {
+ o = msgp.AppendString(o, z.Resources[za0001])
+ }
+ // string "Source"
+ o = append(o, 0xa6, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65)
+ o = msgp.AppendString(o, z.Source)
+ // string "Owner"
+ o = append(o, 0xa5, 0x4f, 0x77, 0x6e, 0x65, 0x72)
+ o = msgp.AppendString(o, z.Owner)
+ // string "Quorum"
+ o = append(o, 0xa6, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d)
+ o = msgp.AppendInt(o, z.Quorum)
+ return
+}
+
+// UnmarshalMsg implements msgp.Unmarshaler
+func (z *LockArgs) UnmarshalMsg(bts []byte) (o []byte, err error) {
+ var field []byte
+ _ = field
+ var zb0001 uint32
+ zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ for zb0001 > 0 {
+ zb0001--
+ field, bts, err = msgp.ReadMapKeyZC(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ switch msgp.UnsafeString(field) {
+ case "UID":
+ z.UID, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "UID")
+ return
+ }
+ case "Resources":
+ var zb0002 uint32
+ zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Resources")
+ return
+ }
+ if cap(z.Resources) >= int(zb0002) {
+ z.Resources = (z.Resources)[:zb0002]
+ } else {
+ z.Resources = make([]string, zb0002)
+ }
+ for za0001 := range z.Resources {
+ z.Resources[za0001], bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Resources", za0001)
+ return
+ }
+ }
+ case "Source":
+ z.Source, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Source")
+ return
+ }
+ case "Owner":
+ z.Owner, bts, err = msgp.ReadStringBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Owner")
+ return
+ }
+ case "Quorum":
+ z.Quorum, bts, err = msgp.ReadIntBytes(bts)
+ if err != nil {
+ err = msgp.WrapError(err, "Quorum")
+ return
+ }
+ default:
+ bts, err = msgp.Skip(bts)
+ if err != nil {
+ err = msgp.WrapError(err)
+ return
+ }
+ }
+ }
+ o = bts
+ return
+}
+
+// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
+func (z *LockArgs) Msgsize() (s int) {
+ s = 1 + 4 + msgp.StringPrefixSize + len(z.UID) + 10 + msgp.ArrayHeaderSize
+ for za0001 := range z.Resources {
+ s += msgp.StringPrefixSize + len(z.Resources[za0001])
+ }
+ s += 7 + msgp.StringPrefixSize + len(z.Source) + 6 + msgp.StringPrefixSize + len(z.Owner) + 7 + msgp.IntSize
+ return
+}
diff --git a/internal/dsync/lock-args_gen_test.go b/internal/dsync/lock-args_gen_test.go
new file mode 100644
index 000000000..7f9c93a21
--- /dev/null
+++ b/internal/dsync/lock-args_gen_test.go
@@ -0,0 +1,123 @@
+package dsync
+
+// Code generated by github.com/tinylib/msgp DO NOT EDIT.
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/tinylib/msgp/msgp"
+)
+
+func TestMarshalUnmarshalLockArgs(t *testing.T) {
+ v := LockArgs{}
+ bts, err := v.MarshalMsg(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ left, err := v.UnmarshalMsg(bts)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(left) > 0 {
+ t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
+ }
+
+ left, err = msgp.Skip(bts)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(left) > 0 {
+ t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
+ }
+}
+
+func BenchmarkMarshalMsgLockArgs(b *testing.B) {
+ v := LockArgs{}
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.MarshalMsg(nil)
+ }
+}
+
+func BenchmarkAppendMsgLockArgs(b *testing.B) {
+ v := LockArgs{}
+ bts := make([]byte, 0, v.Msgsize())
+ bts, _ = v.MarshalMsg(bts[0:0])
+ b.SetBytes(int64(len(bts)))
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bts, _ = v.MarshalMsg(bts[0:0])
+ }
+}
+
+func BenchmarkUnmarshalLockArgs(b *testing.B) {
+ v := LockArgs{}
+ bts, _ := v.MarshalMsg(nil)
+ b.ReportAllocs()
+ b.SetBytes(int64(len(bts)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := v.UnmarshalMsg(bts)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func TestEncodeDecodeLockArgs(t *testing.T) {
+ v := LockArgs{}
+ var buf bytes.Buffer
+ msgp.Encode(&buf, &v)
+
+ m := v.Msgsize()
+ if buf.Len() > m {
+ t.Log("WARNING: TestEncodeDecodeLockArgs Msgsize() is inaccurate")
+ }
+
+ vn := LockArgs{}
+ err := msgp.Decode(&buf, &vn)
+ if err != nil {
+ t.Error(err)
+ }
+
+ buf.Reset()
+ msgp.Encode(&buf, &v)
+ err = msgp.NewReader(&buf).Skip()
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkEncodeLockArgs(b *testing.B) {
+ v := LockArgs{}
+ var buf bytes.Buffer
+ msgp.Encode(&buf, &v)
+ b.SetBytes(int64(buf.Len()))
+ en := msgp.NewWriter(msgp.Nowhere)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.EncodeMsg(en)
+ }
+ en.Flush()
+}
+
+func BenchmarkDecodeLockArgs(b *testing.B) {
+ v := LockArgs{}
+ var buf bytes.Buffer
+ msgp.Encode(&buf, &v)
+ b.SetBytes(int64(buf.Len()))
+ rd := msgp.NewEndlessReader(buf.Bytes(), b)
+ dc := msgp.NewReader(rd)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ err := v.DecodeMsg(dc)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/internal/dsync/rpc-client-interface.go b/internal/dsync/rpc-client-interface.go
index 38ee679f6..5b4578688 100644
--- a/internal/dsync/rpc-client-interface.go
+++ b/internal/dsync/rpc-client-interface.go
@@ -19,26 +19,6 @@ package dsync
import "context"
-// LockArgs is minimal required values for any dsync compatible lock operation.
-type LockArgs struct {
- // Unique ID of lock/unlock request.
- UID string
-
- // Resources contains single or multiple entries to be locked/unlocked.
- Resources []string
-
- // Source contains the line number, function and file name of the code
- // on the client node that requested the lock.
- Source string
-
- // Owner represents unique ID for this instance, an owner who originally requested
- // the locked resource, useful primarily in figuring our stale locks.
- Owner string
-
- // Quorum represents the expected quorum for this lock type.
- Quorum int
-}
-
// NetLocker is dsync compatible locker interface.
type NetLocker interface {
// Do read lock for given LockArgs. It should return
diff --git a/internal/rest/client.go b/internal/rest/client.go
index a6ef07c40..de71aa706 100644
--- a/internal/rest/client.go
+++ b/internal/rest/client.go
@@ -133,7 +133,9 @@ func (c *Client) Call(ctx context.Context, method string, values url.Values, bod
}
req.Header.Set("Authorization", "Bearer "+c.newAuthToken(req.URL.RawQuery))
req.Header.Set("X-Minio-Time", time.Now().UTC().Format(time.RFC3339))
- req.Header.Set("Expect", "100-continue")
+ if body != nil {
+ req.Header.Set("Expect", "100-continue")
+ }
if length > 0 {
req.ContentLength = length
}