mirror of
				https://github.com/minio/minio.git
				synced 2025-11-04 02:01:05 +01:00 
			
		
		
		
	The lock was using net/rpc in the past but it got replaced with a REST API. This commit will fix function names/comments to avoid confusion.
		
			
				
	
	
		
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
package dsync
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"time"
 | 
						|
 | 
						|
	xhttp "github.com/minio/minio/internal/http"
 | 
						|
	"github.com/minio/minio/internal/rest"
 | 
						|
)
 | 
						|
 | 
						|
// ReconnectRESTClient is a wrapper type for rest.Client which provides reconnect on first failure.
 | 
						|
type ReconnectRESTClient struct {
 | 
						|
	u    *url.URL
 | 
						|
	rest *rest.Client
 | 
						|
}
 | 
						|
 | 
						|
// newClient constructs a ReconnectRESTClient object with addr and endpoint initialized.
 | 
						|
// It _doesn't_ connect to the remote endpoint. See Call method to see when the
 | 
						|
// connect happens.
 | 
						|
func newClient(endpoint string) NetLocker {
 | 
						|
	u, err := url.Parse(endpoint)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
 | 
						|
	tr := &http.Transport{
 | 
						|
		Proxy:                 http.ProxyFromEnvironment,
 | 
						|
		MaxIdleConnsPerHost:   1024,
 | 
						|
		WriteBufferSize:       32 << 10, // 32KiB moving up from 4KiB default
 | 
						|
		ReadBufferSize:        32 << 10, // 32KiB moving up from 4KiB default
 | 
						|
		IdleConnTimeout:       15 * time.Second,
 | 
						|
		ResponseHeaderTimeout: 15 * time.Minute, // Set conservative timeouts for MinIO internode.
 | 
						|
		TLSHandshakeTimeout:   15 * time.Second,
 | 
						|
		ExpectContinueTimeout: 15 * time.Second,
 | 
						|
		// Go net/http automatically unzip if content-type is
 | 
						|
		// gzip disable this feature, as we are always interested
 | 
						|
		// in raw stream.
 | 
						|
		DisableCompression: true,
 | 
						|
	}
 | 
						|
 | 
						|
	return &ReconnectRESTClient{
 | 
						|
		u:    u,
 | 
						|
		rest: rest.NewClient(u, tr, nil),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Close closes the underlying socket file descriptor.
 | 
						|
func (restClient *ReconnectRESTClient) IsOnline() bool {
 | 
						|
	// If rest client has not connected yet there is nothing to close.
 | 
						|
	return restClient.rest != nil
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) IsLocal() bool {
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// Close closes the underlying socket file descriptor.
 | 
						|
func (restClient *ReconnectRESTClient) Close() error {
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	errLockConflict = errors.New("lock conflict")
 | 
						|
	errLockNotFound = errors.New("lock not found")
 | 
						|
)
 | 
						|
 | 
						|
func toLockError(err error) error {
 | 
						|
	if err == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch err.Error() {
 | 
						|
	case errLockConflict.Error():
 | 
						|
		return errLockConflict
 | 
						|
	case errLockNotFound.Error():
 | 
						|
		return errLockNotFound
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// Call makes a REST call to the remote endpoint using the msgp codec
 | 
						|
func (restClient *ReconnectRESTClient) Call(method string, args LockArgs) (status bool, err error) {
 | 
						|
	buf, err := args.MarshalMsg(nil)
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	body := bytes.NewReader(buf)
 | 
						|
	respBody, err := restClient.rest.Call(context.Background(), method,
 | 
						|
		url.Values{}, body, body.Size())
 | 
						|
	defer xhttp.DrainBody(respBody)
 | 
						|
 | 
						|
	switch toLockError(err) {
 | 
						|
	case nil:
 | 
						|
		return true, nil
 | 
						|
	case errLockConflict, errLockNotFound:
 | 
						|
		return false, nil
 | 
						|
	default:
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) RLock(ctx context.Context, args LockArgs) (status bool, err error) {
 | 
						|
	return restClient.Call("/v1/rlock", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) Lock(ctx context.Context, args LockArgs) (status bool, err error) {
 | 
						|
	return restClient.Call("/v1/lock", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) RUnlock(ctx context.Context, args LockArgs) (status bool, err error) {
 | 
						|
	return restClient.Call("/v1/runlock", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) Unlock(ctx context.Context, args LockArgs) (status bool, err error) {
 | 
						|
	return restClient.Call("/v1/unlock", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) Refresh(ctx context.Context, args LockArgs) (refreshed bool, err error) {
 | 
						|
	return restClient.Call("/v1/refresh", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) ForceUnlock(ctx context.Context, args LockArgs) (reply bool, err error) {
 | 
						|
	return restClient.Call("/v1/force-unlock", args)
 | 
						|
}
 | 
						|
 | 
						|
func (restClient *ReconnectRESTClient) String() string {
 | 
						|
	return restClient.u.String()
 | 
						|
}
 |