2021-04-19 03:41:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// 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/>.
  
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								package  cmd  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2020-02-02 10:11:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"bufio" 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-20 05:38:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"context" 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"encoding/binary" 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-19 04:07:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"encoding/hex" 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"io" 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-19 04:07:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"net/http" 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-26 14:05:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"os/user" 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"path" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-09 00:41:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"runtime/debug" 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-24 08:31:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-19 08:25:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sync" 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/bpool" 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/grid" 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-03 09:07:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/tinylib/msgp/msgp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-06 03:20:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									jwtreq  "github.com/golang-jwt/jwt/v4/request" 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-20 08:53:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/madmin-go/v3" 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-02 05:59:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/config" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									xhttp  "github.com/minio/minio/internal/http" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-02 23:11:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xioutil  "github.com/minio/minio/internal/ioutil" 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-02 05:59:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xjwt  "github.com/minio/minio/internal/jwt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/logger" 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-23 19:12:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/mux" 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-25 07:05:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xnet  "github.com/minio/pkg/v3/net" 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-05 07:10:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  errDiskStale  =  errors . New ( "drive stale" )  
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// To abstract a disk over network.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type  storageRESTServer  struct  {  
						 
					
						
							
								
									
										
										
										
											2024-02-28 15:02:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									endpoint  Endpoint 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  (  
						 
					
						
							
								
									
										
										
										
											2024-12-12 13:50:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageCheckPartsRPC        =  grid . NewStream [ * CheckPartsHandlerParams ,  grid . NoPayload ,  * CheckPartsResp ] ( grid . HandlerCheckParts3 ,  func ( )  * CheckPartsHandlerParams  {  return  & CheckPartsHandlerParams { }  } ,  nil ,  func ( )  * CheckPartsResp  {  return  & CheckPartsResp { }  } ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-02 07:42:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageDeleteFileRPC        =  grid . NewSingleHandler [ * DeleteFileHandlerParams ,  grid . NoPayload ] ( grid . HandlerDeleteFile ,  func ( )  * DeleteFileHandlerParams  {  return  & DeleteFileHandlerParams { }  } ,  grid . NewNoPayload ) . AllowCallRequestPool ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageDeleteVersionRPC     =  grid . NewSingleHandler [ * DeleteVersionHandlerParams ,  grid . NoPayload ] ( grid . HandlerDeleteVersion ,  func ( )  * DeleteVersionHandlerParams  {  return  & DeleteVersionHandlerParams { }  } ,  grid . NewNoPayload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageDiskInfoRPC          =  grid . NewSingleHandler [ * DiskInfoOptions ,  * DiskInfo ] ( grid . HandlerDiskInfo ,  func ( )  * DiskInfoOptions  {  return  & DiskInfoOptions { }  } ,  func ( )  * DiskInfo  {  return  & DiskInfo { }  } ) . WithSharedResponse ( ) . AllowCallRequestPool ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageNSScannerRPC         =  grid . NewStream [ * nsScannerOptions ,  grid . NoPayload ,  * nsScannerResp ] ( grid . HandlerNSScanner ,  func ( )  * nsScannerOptions  {  return  & nsScannerOptions { }  } ,  nil ,  func ( )  * nsScannerResp  {  return  & nsScannerResp { }  } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageReadAllRPC           =  grid . NewSingleHandler [ * ReadAllHandlerParams ,  * grid . Bytes ] ( grid . HandlerReadAll ,  func ( )  * ReadAllHandlerParams  {  return  & ReadAllHandlerParams { }  } ,  grid . NewBytes ) . AllowCallRequestPool ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageWriteAllRPC          =  grid . NewSingleHandler [ * WriteAllHandlerParams ,  grid . NoPayload ] ( grid . HandlerWriteAll ,  func ( )  * WriteAllHandlerParams  {  return  & WriteAllHandlerParams { }  } ,  grid . NewNoPayload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageReadVersionRPC       =  grid . NewSingleHandler [ * grid . MSS ,  * FileInfo ] ( grid . HandlerReadVersion ,  grid . NewMSS ,  func ( )  * FileInfo  {  return  & FileInfo { }  } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageReadXLRPC            =  grid . NewSingleHandler [ * grid . MSS ,  * RawFileInfo ] ( grid . HandlerReadXL ,  grid . NewMSS ,  func ( )  * RawFileInfo  {  return  & RawFileInfo { }  } ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-24 01:15:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageRenameDataRPC        =  grid . NewSingleHandler [ * RenameDataHandlerParams ,  * RenameDataResp ] ( grid . HandlerRenameData2 ,  func ( )  * RenameDataHandlerParams  {  return  & RenameDataHandlerParams { }  } ,  func ( )  * RenameDataResp  {  return  & RenameDataResp { }  } ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-02 07:42:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageRenameDataInlineRPC  =  grid . NewSingleHandler [ * RenameDataInlineHandlerParams ,  * RenameDataResp ] ( grid . HandlerRenameDataInline ,  newRenameDataInlineHandlerParams ,  func ( )  * RenameDataResp  {  return  & RenameDataResp { }  } ) . AllowCallRequestPool ( false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageRenameFileRPC        =  grid . NewSingleHandler [ * RenameFileHandlerParams ,  grid . NoPayload ] ( grid . HandlerRenameFile ,  func ( )  * RenameFileHandlerParams  {  return  & RenameFileHandlerParams { }  } ,  grid . NewNoPayload ) . AllowCallRequestPool ( true ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageRenamePartRPC        =  grid . NewSingleHandler [ * RenamePartHandlerParams ,  grid . NoPayload ] ( grid . HandlerRenamePart ,  func ( )  * RenamePartHandlerParams  {  return  & RenamePartHandlerParams { }  } ,  grid . NewNoPayload ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-02 07:42:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageStatVolRPC           =  grid . NewSingleHandler [ * grid . MSS ,  * VolInfo ] ( grid . HandlerStatVol ,  grid . NewMSS ,  func ( )  * VolInfo  {  return  & VolInfo { }  } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageUpdateMetadataRPC    =  grid . NewSingleHandler [ * MetadataHandlerParams ,  grid . NoPayload ] ( grid . HandlerUpdateMetadata ,  func ( )  * MetadataHandlerParams  {  return  & MetadataHandlerParams { }  } ,  grid . NewNoPayload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageWriteMetadataRPC     =  grid . NewSingleHandler [ * MetadataHandlerParams ,  grid . NoPayload ] ( grid . HandlerWriteMetadata ,  func ( )  * MetadataHandlerParams  {  return  & MetadataHandlerParams { }  } ,  grid . NewNoPayload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageListDirRPC           =  grid . NewStream [ * grid . MSS ,  grid . NoPayload ,  * ListDirResult ] ( grid . HandlerListDir ,  grid . NewMSS ,  nil ,  func ( )  * ListDirResult  {  return  & ListDirResult { }  } ) . WithOutCapacity ( 1 ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-28 15:02:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  getStorageViaEndpoint ( endpoint  Endpoint )  StorageAPI  {  
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalLocalDrivesMu . RLock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  globalLocalDrivesMu . RUnlock ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 05:23:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( globalLocalSetDrives )  ==  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-23 07:07:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  globalLocalDrivesMap [ endpoint . String ( ) ] 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 05:23:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-28 15:02:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  globalLocalSetDrives [ endpoint . PoolIdx ] [ endpoint . SetIdx ] [ endpoint . DiskIdx ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  getStorage ( )  StorageAPI  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  getStorageViaEndpoint ( s . endpoint ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  writeErrorResponse ( w  http . ResponseWriter ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2023-07-15 09:34:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  =  unwrapAll ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  err  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  errDiskStale : 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-18 05:49:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										w . WriteHeader ( http . StatusPreconditionFailed ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-15 09:34:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errFileNotFound ,  errFileVersionNotFound : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										w . WriteHeader ( http . StatusNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  errInvalidAccessKeyID ,  errAccessKeyDisabled ,  errNoAuthToken ,  errMalformedAuth ,  errAuthentication ,  errSkewedAuthTime : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										w . WriteHeader ( http . StatusUnauthorized ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-23 02:10:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  context . Canceled ,  context . DeadlineExceeded : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										w . WriteHeader ( 499 ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-15 09:34:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-18 05:49:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										w . WriteHeader ( http . StatusForbidden ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									w . Write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-18 14:16:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// DefaultSkewTime - skew time is 15 minutes between minio peers.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  DefaultSkewTime  =  15  *  time . Minute  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-09 05:44:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// validateStorageRequestToken will validate the token against the provided audience.
  
						 
					
						
							
								
									
										
										
										
											2024-07-22 15:04:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  validateStorageRequestToken ( token  string )  error  {  
						 
					
						
							
								
									
										
										
										
											2020-01-31 10:59:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									claims  :=  xjwt . NewStandardClaims ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-09 05:44:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  xjwt . ParseWithStandardClaims ( token ,  claims ,  [ ] byte ( globalActiveCred . SecretKey ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-31 10:59:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errAuthentication 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									owner  :=  claims . AccessKey  ==  globalActiveCred . AccessKey  ||  claims . Subject  ==  globalActiveCred . AccessKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! owner  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errAuthentication 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-09 05:44:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Authenticates storage client's requests and validates for skewed time.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  storageServerRequestValidate ( r  * http . Request )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									token ,  err  :=  jwtreq . AuthorizationHeaderExtractor . ExtractToken ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  jwtreq . ErrNoTokenInRequest  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  errNoAuthToken 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errMalformedAuth 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-22 15:04:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  =  validateStorageRequestToken ( token ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-09 05:44:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-31 10:59:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-22 15:04:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									nanoTime ,  err  :=  strconv . ParseInt ( r . Header . Get ( "X-Minio-Time" ) ,  10 ,  64 ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-15 09:34:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errMalformedAuth 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-22 15:04:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									localTime  :=  UTCNow ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									remoteTime  :=  time . Unix ( 0 ,  nanoTime ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delta  :=  remoteTime . Sub ( localTime ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  delta  <  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-31 10:59:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										delta  *=  - 1 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-22 15:04:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  delta  >  DefaultSkewTime  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-15 09:34:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errSkewedAuthTime 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-31 10:59:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// IsAuthValid - To authenticate and verify the time difference.
  
						 
					
						
							
								
									
										
										
										
											2022-03-02 07:06:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  IsAuthValid ( w  http . ResponseWriter ,  r  * http . Request )  bool  {  
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  s . getStorage ( )  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-24 03:00:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  errDiskNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  storageServerRequestValidate ( r ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-17 12:14:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-02 07:06:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// IsValid - To authenticate and check if the disk-id in the request corresponds to the underlying disk.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  IsValid ( w  http . ResponseWriter ,  r  * http . Request )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsAuthValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  r . ParseForm ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-08 13:43:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									diskID  :=  r . Form . Get ( storageRESTDiskID ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:37:53 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  diskID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Request sent empty disk-id, we allow the request
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// as the peer might be coming up and trying to read format.json
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// or create format.json
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-17 12:14:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storedDiskID ,  err  :=  s . getStorage ( ) . GetDiskID ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-22 04:54:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-22 04:54:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  diskID  !=  storedDiskID  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  errDiskStale ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// If format.json is available and request sent the right disk-id, we allow the request
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-14 07:29:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// checkID - check if the disk-id in the request corresponds to the underlying disk.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  checkID ( wantID  string )  bool  {  
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  s . getStorage ( )  ==  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  wantID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Request sent empty disk-id, we allow the request
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// as the peer might be coming up and trying to read format.json
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// or create format.json
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storedDiskID ,  err  :=  s . getStorage ( ) . GetDiskID ( ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  wantID  ==  storedDiskID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-18 05:49:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// HealthHandler handler checks if disk is stale
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  HealthHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									s . IsValid ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// DiskInfoHandler - returns disk info.
  
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  DiskInfoHandler ( opts  * DiskInfoOptions )  ( * DiskInfo ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( opts . DiskID )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									info ,  err  :=  s . getStorage ( ) . DiskInfo ( context . Background ( ) ,  * opts ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-14 00:51:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										info . Error  =  err . Error ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & info ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  NSScannerHandler ( ctx  context . Context ,  params  * nsScannerOptions ,  out  chan <-  * nsScannerResp )  * grid . RemoteErr  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( params . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-07 23:10:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  params . Cache  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewRemoteErrString ( "NSScannerHandler: provided cache is nil" ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-12 22:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-05-20 05:38:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Collect updates, stream them before the full cache is sent.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									updates  :=  make ( chan  dataUsageEntry ,  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  wg  sync . WaitGroup 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									wg . Add ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										defer  wg . Done ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  update  :=  range  updates  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											resp  :=  storageNSScannerRPC . NewResponse ( ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											resp . Update  =  & update 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											out  <-  resp 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-20 05:38:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-03 05:51:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ui ,  err  :=  s . getStorage ( ) . NSScanner ( ctx ,  * params . Cache ,  updates ,  madmin . HealScanMode ( params . ScanMode ) ,  nil ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-20 05:38:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wg . Wait ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-03 02:19:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-03 02:19:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Send final response.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									resp  :=  storageNSScannerRPC . NewResponse ( ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									resp . Final  =  & ui 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									out  <-  resp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-12 22:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// MakeVolHandler - make a volume.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  MakeVolHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  s . getStorage ( ) . MakeVol ( r . Context ( ) ,  volume ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-12-24 08:31:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// MakeVolBulkHandler - create multiple volumes as a bulk operation.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  MakeVolBulkHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volumes  :=  strings . Split ( r . Form . Get ( storageRESTVolumes ) ,  "," ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  s . getStorage ( ) . MakeVolBulk ( r . Context ( ) ,  volumes ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-24 08:31:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// StatVolHandler - stat a volume.
  
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  StatVolHandler ( params  * grid . MSS )  ( * VolInfo ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( params . Get ( storageRESTDiskID ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									info ,  err  :=  s . getStorage ( ) . StatVol ( context . Background ( ) ,  params . Get ( storageRESTVolume ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & info ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// AppendFileHandler - append data from the request to the file specified.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  AppendFileHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf  :=  make ( [ ] byte ,  r . ContentLength ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									_ ,  err  :=  io . ReadFull ( r . Body ,  buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  =  s . getStorage ( ) . AppendFile ( r . Context ( ) ,  volume ,  filePath ,  buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-19 03:41:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// CreateFileHandler - copy the contents from the request.
  
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  CreateFileHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									origvolume  :=  r . Form . Get ( storageRESTOrigVolume ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fileSizeStr  :=  r . Form . Get ( storageRESTLength ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fileSize ,  err  :=  strconv . Atoi ( fileSizeStr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-25 00:05:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done ,  body  :=  keepHTTPReqResponseAlive ( w ,  r ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done ( s . getStorage ( ) . CreateFile ( r . Context ( ) ,  origvolume ,  volume ,  filePath ,  int64 ( fileSize ) ,  body ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// DeleteVersionHandler delete updated metadata.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  DeleteVersionHandler ( p  * DeleteVersionHandlerParams )  ( np  grid . NoPayload ,  gerr  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  np ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-27 07:49:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									forceDelMarker  :=  p . ForceDelMarker 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-27 07:49:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-30 07:52:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									opts  :=  DeleteOptions { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									err  :=  s . getStorage ( ) . DeleteVersion ( context . Background ( ) ,  volume ,  filePath ,  p . FI ,  forceDelMarker ,  opts ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  np ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ReadVersionHandlerWS read metadata of versionID
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadVersionHandlerWS ( params  * grid . MSS )  ( * FileInfo ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( params . Get ( storageRESTDiskID ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									origvolume  :=  params . Get ( storageRESTOrigVolume ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  params . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  params . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									versionID  :=  params . Get ( storageRESTVersionID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-24 01:20:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 13:33:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									healing ,  err  :=  strconv . ParseBool ( params . Get ( storageRESTHealing ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-06-17 22:29:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									inclFreeVersions ,  err  :=  strconv . ParseBool ( params . Get ( storageRESTInclFreeVersions ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									fi ,  err  :=  s . getStorage ( ) . ReadVersion ( context . Background ( ) ,  origvolume ,  volume ,  filePath ,  versionID ,  ReadOptions { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										InclFreeVersions :  inclFreeVersions , 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ReadData :          false , 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-17 22:29:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Healing :           healing , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & fi ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadVersionHandler read metadata of versionID
  
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadVersionHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									origvolume  :=  r . Form . Get ( storageRESTOrigVolume ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									versionID  :=  r . Form . Get ( storageRESTVersionID ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 13:33:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									healing ,  err  :=  strconv . ParseBool ( r . Form . Get ( storageRESTHealing ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-17 22:29:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									inclFreeVersions ,  err  :=  strconv . ParseBool ( r . Form . Get ( storageRESTInclFreeVersions ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									fi ,  err  :=  s . getStorage ( ) . ReadVersion ( r . Context ( ) ,  origvolume ,  volume ,  filePath ,  versionID ,  ReadOptions { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										InclFreeVersions :  inclFreeVersions , 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ReadData :          true , 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-17 22:29:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Healing :           healing , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-08 11:27:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageLogIf ( r . Context ( ) ,  msgp . Encode ( w ,  & fi ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// WriteMetadataHandler rpc handler to write new updated metadata.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  WriteMetadataHandler ( p  * MetadataHandlerParams )  ( np  grid . NoPayload ,  gerr  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									origvolume  :=  p . OrigVolume 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  s . getStorage ( ) . WriteMetadata ( context . Background ( ) ,  origvolume ,  volume ,  filePath ,  p . FI ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  np ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// UpdateMetadataHandler update new updated metadata.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  UpdateMetadataHandler ( p  * MetadataHandlerParams )  ( grid . NoPayload ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-05 04:32:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-05 04:32:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  grid . NewNPErr ( s . getStorage ( ) . UpdateMetadata ( context . Background ( ) ,  volume ,  filePath ,  p . FI ,  p . UpdateOpts ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-05 04:32:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-12 13:50:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// CheckPartsHandler - check if a file parts exists.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  CheckPartsHandler ( ctx  context . Context ,  p  * CheckPartsHandlerParams ,  out  chan <-  * CheckPartsResp )  * grid . RemoteErr  {  
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-12 13:50:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-10 23:51:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-12 13:50:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									resp ,  err  :=  s . getStorage ( ) . CheckParts ( ctx ,  volume ,  filePath ,  p . FI ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									out  <-  resp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 01:54:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  WriteAllHandler ( p  * WriteAllHandlerParams )  ( grid . NoPayload ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  grid . NewNPErr ( s . getStorage ( ) . WriteAll ( context . Background ( ) ,  volume ,  filePath ,  p . Buf ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ReadAllHandler - read all the contents of a file.
  
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadAllHandler ( p  * ReadAllHandlerParams )  ( * grid . Bytes ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  p . Volume 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  p . FilePath 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf ,  err  :=  s . getStorage ( ) . ReadAll ( context . Background ( ) ,  volume ,  filePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  grid . NewBytesWith ( buf ) ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-21 03:49:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadXLHandler - read xl.meta for an object at path.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadXLHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-21 03:49:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									rf ,  err  :=  s . getStorage ( ) . ReadXL ( r . Context ( ) ,  volume ,  filePath ,  true ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-21 03:49:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									storageLogIf ( r . Context ( ) ,  msgp . Encode ( w ,  & rf ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-21 03:49:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadXLHandlerWS - read xl.meta for an object at path.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadXLHandlerWS ( params  * grid . MSS )  ( * RawFileInfo ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( params . Get ( storageRESTDiskID ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  params . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  params . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									rf ,  err  :=  s . getStorage ( ) . ReadXL ( context . Background ( ) ,  volume ,  filePath ,  false ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & rf ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadPartsHandler - read section of a file.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadPartsHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  preq  ReadPartsReq 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  msgp . Decode ( r . Body ,  & preq ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									done  :=  keepHTTPResponseAlive ( w ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									infos ,  err  :=  s . getStorage ( ) . ReadParts ( r . Context ( ) ,  volume ,  preq . Paths ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									done ( nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									presp  :=  & ReadPartsResp { Infos :  infos } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageLogIf ( r . Context ( ) ,  msgp . Encode ( w ,  presp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ReadFileHandler - read section of a file.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadFileHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									offset ,  err  :=  strconv . Atoi ( r . Form . Get ( storageRESTOffset ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									length ,  err  :=  strconv . Atoi ( r . Form . Get ( storageRESTLength ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  offset  <  0  ||  length  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  errInvalidArgument ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  verifier  * BitrotVerifier 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  r . Form . Get ( storageRESTBitrotAlgo )  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										hashStr  :=  r . Form . Get ( storageRESTBitrotHash ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										var  hash  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										hash ,  err  =  hex . DecodeString ( hashStr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										verifier  =  NewBitrotVerifier ( BitrotAlgorithmFromString ( r . Form . Get ( storageRESTBitrotAlgo ) ) ,  hash ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf  :=  make ( [ ] byte ,  length ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-29 08:02:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  metaDataPoolPut ( buf )  // Reuse if we can.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									_ ,  err  =  s . getStorage ( ) . ReadFile ( r . Context ( ) ,  volume ,  filePath ,  int64 ( offset ) ,  buf ,  verifier ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-03 13:34:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									w . Header ( ) . Set ( xhttp . ContentLength ,  strconv . Itoa ( len ( buf ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									w . Write ( buf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadFileStreamHandler - read section of a file.
  
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadFileStreamHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-24 18:22:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									offset ,  err  :=  strconv . ParseInt ( r . Form . Get ( storageRESTOffset ) ,  10 ,  64 ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-24 18:22:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									length ,  err  :=  strconv . ParseInt ( r . Form . Get ( storageRESTLength ) ,  10 ,  64 ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-18 13:20:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-24 18:22:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									rc ,  err  :=  s . getStorage ( ) . ReadFileStream ( r . Context ( ) ,  volume ,  filePath ,  offset ,  length ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  rc . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-09-26 14:08:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-11-11 02:10:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									_ ,  err  =  xioutil . Copy ( w ,  rc ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! xnet . IsNetworkOrHostDown ( err ,  true )  {  // do not need to log disconnected clients
 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										storageLogIf ( r . Context ( ) ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-01 07:33:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ListDirHandler - list a directory.
  
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ListDirHandler ( ctx  context . Context ,  params  * grid . MSS ,  out  chan <-  * ListDirResult )  * grid . RemoteErr  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( params . Get ( storageRESTDiskID ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  params . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dirPath  :=  params . Get ( storageRESTDirPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									origvolume  :=  params . Get ( storageRESTOrigVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									count ,  err  :=  strconv . Atoi ( params . Get ( storageRESTCount ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-22 13:10:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									entries ,  err  :=  s . getStorage ( ) . ListDir ( ctx ,  origvolume ,  volume ,  dirPath ,  count ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									out  <-  & ListDirResult { Entries :  entries } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DeleteFileHandler - delete a file.
  
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  DeleteFileHandler ( p  * DeleteFileHandlerParams )  ( grid . NoPayload ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  grid . NewNPErr ( s . getStorage ( ) . Delete ( context . Background ( ) ,  p . Volume ,  p . FilePath ,  p . Opts ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// DeleteVersionsHandler - delete a set of a versions.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  DeleteVersionsHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
									
										
										
										
											2019-05-14 03:25:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-08 13:43:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									totalVersions ,  err  :=  strconv . Atoi ( r . Form . Get ( storageRESTTotalVersions ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-02-02 10:11:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-05-14 03:25:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-02 01:50:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									versions  :=  make ( [ ] FileInfoVersions ,  totalVersions ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-07 07:02:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									decoder  :=  msgpNewReader ( r . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  readMsgpReaderPoolPut ( decoder ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-05-27 23:19:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  i  :=  range  totalVersions  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-03 09:07:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										dst  :=  & versions [ i ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  :=  dst . DecodeMsg ( decoder ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done  :=  keepHTTPResponseAlive ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-30 07:52:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									opts  :=  DeleteOptions { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errs  :=  s . getStorage ( ) . DeleteVersions ( r . Context ( ) ,  volume ,  versions ,  opts ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done ( nil ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dErrsResp  :=  & DeleteVersionsErrsResp { Errs :  make ( [ ] string ,  totalVersions ) } 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  idx  :=  range  versions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  errs [ idx ]  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											dErrsResp . Errs [ idx ]  =  errs [ idx ] . Error ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-01 10:01:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf ,  _  :=  dErrsResp . MarshalMsg ( nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									w . Write ( buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-11 23:56:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// RenameDataHandler - renames a meta object and data dir to destination.
  
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  RenameDataHandler ( p  * RenameDataHandlerParams )  ( * RenameDataResp ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  grid . NewRemoteErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-21 01:44:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-24 01:15:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									resp ,  err  :=  s . getStorage ( ) . RenameData ( context . Background ( ) ,  p . SrcVolume ,  p . SrcPath ,  p . FI ,  p . DstVolume ,  p . DstPath ,  p . Opts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & resp ,  grid . NewRemoteErr ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-02 07:42:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// RenameDataInlineHandler - renames a meta object and data dir to destination.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  RenameDataInlineHandler ( p  * RenameDataInlineHandlerParams )  ( * RenameDataResp ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  p . Recycle ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  s . RenameDataHandler ( & p . RenameDataHandlerParams ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-05-14 03:25:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// RenameFileHandler - rename a file from source to destination
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  RenameFileHandler ( p  * RenameFileHandlerParams )  ( grid . NoPayload ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-26 04:45:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  grid . NewNPErr ( s . getStorage ( ) . RenameFile ( context . Background ( ) ,  p . SrcVolume ,  p . SrcFilePath ,  p . DstVolume ,  p . DstFilePath ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// RenamePartHandler - rename a multipart part from source to destination
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  RenamePartHandler ( p  * RenamePartHandlerParams )  ( grid . NoPayload ,  * grid . RemoteErr )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . checkID ( p . DiskID )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  grid . NewNPErr ( errDiskNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-25 13:41:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  grid . NewNPErr ( s . getStorage ( ) . RenamePart ( context . Background ( ) ,  p . SrcVolume ,  p . SrcFilePath ,  p . DstVolume ,  p . DstFilePath ,  p . Meta ,  p . SkipParent ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 02:20:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// CleanAbandonedDataHandler - Clean unused data directories.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  CleanAbandonedDataHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  volume  ==  ""  ||  filePath  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  // Ignore
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									keepHTTPResponseAlive ( w ) ( s . getStorage ( ) . CleanAbandonedData ( r . Context ( ) ,  volume ,  filePath ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-29 02:20:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// closeNotifier is itself a ReadCloser that will notify when either an error occurs or
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// the Close() function is called.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type  closeNotifier  struct  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rc    io . ReadCloser 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									done  chan  struct { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * closeNotifier )  Read ( p  [ ] byte )  ( n  int ,  err  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									n ,  err  =  c . rc . Read ( p ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  c . done  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											xioutil . SafeClose ( c . done ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											c . done  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  n ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * closeNotifier )  Close ( )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  c . done  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										xioutil . SafeClose ( c . done ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										c . done  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  c . rc . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// keepHTTPReqResponseAlive can be used to avoid timeouts with long storage
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// operations, such as bitrot verification or data usage scanning.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Every 10 seconds a space character is sent.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// keepHTTPReqResponseAlive will wait for the returned body to be read before starting the ticker.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The returned function should always be called to release resources.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// An optional error can be sent which will be picked as text only error,
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// without its original type by the receiver.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// waitForHTTPResponse should be used to the receiving side.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  keepHTTPReqResponseAlive ( w  http . ResponseWriter ,  r  * http . Request )  ( resp  func ( error ) ,  body  io . ReadCloser )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									bodyDoneCh  :=  make ( chan  struct { } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									doneCh  :=  make ( chan  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ctx  :=  r . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-03 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										canWrite  :=  true 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										write  :=  func ( b  [ ] byte )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  canWrite  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												n ,  err  :=  w . Write ( b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  ||  n  !=  len ( b )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													canWrite  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Wait for body to be read.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  <- ctx . Done ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  <- bodyDoneCh : 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											xioutil . SafeClose ( doneCh ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										defer  xioutil . SafeClose ( doneCh ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Initiate ticker after body has been read.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ticker  :=  time . NewTicker ( time . Second  *  10 ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-29 01:53:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										defer  ticker . Stop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  <- ticker . C : 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-29 01:53:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// The done() might have been called
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// concurrently, check for it before we
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// write the filler byte.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// Response not ready, write a filler byte.
 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( [ ] byte { 32 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  canWrite  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													xhttp . Flush ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  func ( err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  doneCh  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Indicate we are ready to write.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										doneCh  <-  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Wait for channel to be closed so we don't race on writes.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										<- doneCh 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Clear so we can be called multiple times without crashing.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										doneCh  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ,  & closeNotifier { rc :  r . Body ,  done :  bodyDoneCh } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// keepHTTPResponseAlive can be used to avoid timeouts with long storage
  
						 
					
						
							
								
									
										
										
										
											2021-02-27 07:11:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// operations, such as bitrot verification or data usage scanning.
  
						 
					
						
							
								
									
										
										
										
											2021-08-28 00:16:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// keepHTTPResponseAlive may NOT be used until the request body has been read,
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// use keepHTTPReqResponseAlive instead.
  
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Every 10 seconds a space character is sent.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The returned function should always be called to release resources.
  
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// An optional error can be sent which will be picked as text only error,
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// without its original type by the receiver.
  
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// waitForHTTPResponse should be used to the receiving side.
  
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  keepHTTPResponseAlive ( w  http . ResponseWriter )  func ( error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									doneCh  :=  make ( chan  error ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-03 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										canWrite  :=  true 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										write  :=  func ( b  [ ] byte )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  canWrite  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												n ,  err  :=  w . Write ( b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  ||  n  !=  len ( b )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													canWrite  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										defer  xioutil . SafeClose ( doneCh ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ticker  :=  time . NewTicker ( time . Second  *  10 ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										defer  ticker . Stop ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  <- ticker . C : 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-29 01:53:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// The done() might have been called
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// concurrently, check for it before we
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// write the filler byte.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// Response not ready, write a filler byte.
 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( [ ] byte { 32 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  canWrite  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													xhttp . Flush ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												Fix panic (not fatal) on connection drops (#13811)
Fix more regressions from #13597 with double closed channels.
```
panic: "POST /minio/storage/data/distxl-plain/s1/d2/v42/createfile?disk-id=c789f7e1-2b52-442a-b518-aa2dac03f3a1&file-path=f6161668-b939-4543-9873-91b9da4cdff6%2F5eafa986-a3bf-4b1c-8bc0-03a37de390a3%2Fpart.1&length=2621760&volume=.minio.sys%2Ftmp": send on closed channel
goroutine 1977 [running]:
runtime/debug.Stack()
        c:/go/src/runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        d:/minio/minio/cmd/generic-handlers.go:468 +0x8e
panic({0x2928860, 0x4fb17e0})
        c:/go/src/runtime/panic.go:1038 +0x215
github.com/minio/minio/cmd.keepHTTPReqResponseAlive.func2({0x4fe4ea0, 0xc02737d8a0})
        d:/minio/minio/cmd/storage-rest-server.go:818 +0x48
github.com/minio/minio/cmd.(*storageRESTServer).CreateFileHandler(0xc0015a8510, {0x50073e0, 0xc0273ec460}, 0xc029b9a400)
        d:/minio/minio/cmd/storage-rest-server.go:334 +0x1d2
net/http.HandlerFunc.ServeHTTP(...)
        c:/go/src/net/http/server.go:2046
github.com/minio/minio/cmd.httpTraceHdrs.func1({0x50073e0, 0xc0273ec460}, 0x0)
        d:/minio/minio/cmd/handler-utils.go:372 +0x53
net/http.HandlerFunc.ServeHTTP(0x5007380, {0x50073e0, 0xc0273ec460}, 0x10)
        c:/go/src/net/http/server.go:2046 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x5007380, 0xc0273dcf00}, 0xc0273f7340)
```
Reverts but adds write checks.
											 
										 
										
											2021-12-03 03:22:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  func ( err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  doneCh  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Indicate we are ready to write.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										doneCh  <-  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Wait for channel to be closed so we don't race on writes.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										<- doneCh 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Clear so we can be called multiple times without crashing.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										doneCh  =  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// waitForHTTPResponse will wait for responses where keepHTTPResponseAlive
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// has been used.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The returned reader contains the payload.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  waitForHTTPResponse ( respBody  io . Reader )  ( io . Reader ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									reader  :=  bufio . NewReader ( respBody ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										b ,  err  :=  reader . ReadByte ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Check if we have a response ready or a filler byte.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										switch  b  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  0 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  reader ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  1 : 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-20 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											errorText ,  err  :=  io . ReadAll ( reader ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-12 11:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  errors . New ( string ( errorText ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  32 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  fmt . Errorf ( "unexpected filler byte: %d" ,  b ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// httpStreamResponse allows streaming a response, but still send an error.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type  httpStreamResponse  struct  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									done   chan  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									block  chan  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									err    error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 23:26:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Write part of the streaming response.
  
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Note that upstream errors are currently not forwarded, but may be in the future.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( h  * httpStreamResponse )  Write ( b  [ ] byte )  ( int ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2020-11-12 10:07:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( b )  ==  0  ||  h . err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Ignore 0 length blocks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ,  h . err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									tmp  :=  make ( [ ] byte ,  len ( b ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									copy ( tmp ,  b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									h . block  <-  tmp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  len ( b ) ,  h . err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// CloseWithError will close the stream and return the specified error.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// This can be done several times, but only the first error will be sent.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// After calling this the stream should not be written to.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( h  * httpStreamResponse )  CloseWithError ( err  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  h . done  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									h . done  <-  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									h . err  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Indicates that the response is done.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									<- h . done 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									h . done  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// streamHTTPResponse can be used to avoid timeouts with long storage
  
						 
					
						
							
								
									
										
										
										
											2021-02-27 07:11:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// operations, such as bitrot verification or data usage scanning.
  
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Every 10 seconds a space character is sent.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The returned function should always be called to release resources.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// An optional error can be sent which will be picked as text only error,
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// without its original type by the receiver.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// waitForHTTPStream should be used to the receiving side.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  streamHTTPResponse ( w  http . ResponseWriter )  * httpStreamResponse  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									doneCh  :=  make ( chan  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									blockCh  :=  make ( chan  [ ] byte ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									h  :=  httpStreamResponse { done :  doneCh ,  block :  blockCh } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-03 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										canWrite  :=  true 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-25 01:42:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										write  :=  func ( b  [ ] byte )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  canWrite  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												n ,  err  :=  w . Write ( b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  ||  n  !=  len ( b )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													canWrite  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ticker  :=  time . NewTicker ( time . Second  *  10 ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										defer  ticker . Stop ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  <- ticker . C : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// Response not ready, write a filler byte.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-25 01:42:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( [ ] byte { 32 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  canWrite  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													xhttp . Flush ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											case  err  :=  <- doneCh : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-25 01:42:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 1 } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													write ( [ ] byte ( err . Error ( ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-25 01:42:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													write ( [ ] byte { 0 } ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-29 02:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												xioutil . SafeClose ( doneCh ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  block  :=  <- blockCh : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												var  tmp  [ 5 ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												tmp [ 0 ]  =  2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												binary . LittleEndian . PutUint32 ( tmp [ 1 : ] ,  uint32 ( len ( block ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-25 01:42:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												write ( tmp [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												write ( block ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  canWrite  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													xhttp . Flush ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 09:19:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & h 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  poolBuf8k  =  bpool . Pool [ * [ ] byte ] {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									New :  func ( )  * [ ] byte  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-02 23:11:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										b  :=  make ( [ ] byte ,  8192 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  & b 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// waitForHTTPStream will wait for responses where
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// streamHTTPResponse has been used.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The returned reader contains the payload and must be closed if no error is returned.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  waitForHTTPStream ( respBody  io . ReadCloser ,  w  io . Writer )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  tmp  [ 1 ] byte 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-08 00:11:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// 8K copy buffer, reused for less allocs...
 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									bufp  :=  poolBuf8k . Get ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-02 23:11:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									buf  :=  * bufp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  poolBuf8k . Put ( bufp ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-19 00:25:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										_ ,  err  :=  io . ReadFull ( respBody ,  tmp [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Check if we have a response ready or a filler byte.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										switch  tmp [ 0 ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  0 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// 0 is unbuffered, copy the rest.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-02 23:11:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											_ ,  err  :=  io . CopyBuffer ( w ,  respBody ,  buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  ==  io . EOF  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  1 : 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-20 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											errorText ,  err  :=  io . ReadAll ( respBody ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  errors . New ( string ( errorText ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  2 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Block of data
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											var  tmp  [ 4 ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											_ ,  err  :=  io . ReadFull ( respBody ,  tmp [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											length  :=  binary . LittleEndian . Uint32 ( tmp [ : ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-03 00:16:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											n ,  err  :=  io . CopyBuffer ( w ,  io . LimitReader ( respBody ,  int64 ( length ) ) ,  buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-03 00:16:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  n  !=  int64 ( length )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  io . ErrUnexpectedEOF 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-29 00:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  32 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "unexpected filler byte: %d" ,  tmp [ 0 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// VerifyFileHandler - Verify all part of file for bitrot errors.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  VerifyFileHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  r . ContentLength  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  errInvalidArgument ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-13 07:29:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  fi  FileInfo 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-03 09:07:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  msgp . Decode ( r . Body ,  & fi ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-19 07:19:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done  :=  keepHTTPResponseAlive ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-10 23:51:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									resp ,  err  :=  s . getStorage ( ) . VerifyFile ( r . Context ( ) ,  volume ,  filePath ,  fi ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-02 04:12:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-10 23:51:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-02 04:12:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-10 23:51:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									buf ,  _  :=  resp . MarshalMsg ( nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									w . Write ( buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-09 04:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-04 01:25:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  checkDiskFatalErrs ( errs  [ ] error )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// This returns a common error if all errors are
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// same errors, then there is no point starting
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// the server.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errUnsupportedDisk )  ==  len ( errs )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errUnsupportedDisk 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errDiskAccessDenied )  ==  len ( errs )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errDiskAccessDenied 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errFileAccessDenied )  ==  len ( errs )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-16 23:20:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errFileAccessDenied 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-04 01:25:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errDiskNotDir )  ==  len ( errs )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errDiskNotDir 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errFaultyDisk )  ==  len ( errs )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errFaultyDisk 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-05-31 01:58:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  countErrs ( errs ,  errXLBackend )  ==  len ( errs )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errXLBackend 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-04 01:25:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// A single function to write certain errors to be fatal
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// or informative based on the `exit` flag, please look
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// at each implementation of error for added hints.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// FIXME: This is an unusual function but serves its purpose for
  
						 
					
						
							
								
									
										
										
										
											2024-01-18 15:03:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// now, need to revisit the overall erroring structure here.
  
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Do not like it :-(
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  logFatalErrs ( err  error ,  endpoint  Endpoint ,  exit  bool )  {  
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									switch  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-31 01:58:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errXLBackend ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrInvalidXLValue ( err ) ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errUnsupportedDisk ) : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										var  hint  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  endpoint . URL  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-05 07:10:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											hint  =  fmt . Sprintf ( "Drive '%s' does not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support" ,  endpoint . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-05 07:10:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											hint  =  "Drives do not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support" 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-15 01:11:51 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrUnsupportedBackend ( err ) . Hint ( "%s" ,  hint ) ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errDiskNotDir ) : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										var  hint  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  endpoint . URL  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-05 07:10:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											hint  =  fmt . Sprintf ( "Drive '%s' is not a directory, MinIO erasure coding needs a directory" ,  endpoint . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-05 07:10:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											hint  =  "Drives are not directories, MinIO erasure coding needs directories" 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-15 01:11:51 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrUnableToWriteInBackend ( err ) . Hint ( "%s" ,  hint ) ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-04 01:25:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errDiskAccessDenied ) : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Show a descriptive error with a hint about how to fix it.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  username  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  u ,  err  :=  user . Current ( ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											username  =  u . Username 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											username  =  "<your-username>" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  hint  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  endpoint . URL  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											hint  =  fmt . Sprintf ( "Run the following command to add write permissions: `sudo chown -R %s %s && sudo chmod u+rxw %s`" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												username ,  endpoint . Path ,  endpoint . Path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											hint  =  fmt . Sprintf ( "Run the following command to add write permissions: `sudo chown -R %s. <path> && sudo chmod u+rxw <path>`" ,  username ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ! exit  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											storageLogOnceIf ( GlobalContext ,  fmt . Errorf ( "Drive is not writable %s, %s" ,  endpoint ,  hint ) ,  "log-fatal-errs" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-15 01:11:51 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . Fatal ( config . ErrUnableToWriteInBackend ( err ) . Hint ( "%s" ,  hint ) ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errFaultyDisk ) : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ! exit  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											storageLogOnceIf ( GlobalContext ,  fmt . Errorf ( "Drive is faulty at %s, please replace the drive - drive will be offline" ,  endpoint ) ,  "log-fatal-errs" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( err ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errDiskFull ) : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ! exit  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											storageLogOnceIf ( GlobalContext ,  fmt . Errorf ( "Drive is already full at %s, incoming I/O will fail - drive will be offline" ,  endpoint ) ,  "log-fatal-errs" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( err ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-12 01:45:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  errors . Is ( err ,  errInconsistentDisk ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  exit  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( err ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-16 03:56:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ! exit  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											storageLogOnceIf ( GlobalContext ,  fmt . Errorf ( "Drive %s returned an unexpected error: %w, please investigate - drive will be offline" ,  endpoint ,  err ) ,  "log-fatal-errs" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( err ,  "Unable to initialize backend" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-07-10 02:29:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// StatInfoFile returns file stat info.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  StatInfoFile ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-10 00:38:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									filePath  :=  r . Form . Get ( storageRESTFilePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									glob  :=  r . Form . Get ( storageRESTGlob ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-10 02:29:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done  :=  keepHTTPResponseAlive ( w ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									stats ,  err  :=  s . getStorage ( ) . StatInfoFile ( r . Context ( ) ,  volume ,  filePath ,  glob  ==  "true" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-10 02:29:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									done ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-02 02:50:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  si  :=  range  stats  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										msgp . Encode ( w ,  & si ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-10 02:29:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  DeleteBulkHandler ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  req  DeleteBulkReq 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									mr  :=  msgpNewReader ( r . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  readMsgpReaderPoolPut ( mr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  req . DecodeMsg ( mr ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s . writeErrorResponse ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									volume  :=  r . Form . Get ( storageRESTVolume ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									keepHTTPResponseAlive ( w ) ( s . getStorage ( ) . DeleteBulk ( r . Context ( ) ,  volume ,  req . Paths ... ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// ReadMultiple returns multiple files
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( s  * storageRESTServer )  ReadMultiple ( w  http . ResponseWriter ,  r  * http . Request )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! s . IsValid ( w ,  r )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rw  :=  streamHTTPResponse ( w ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  r  :=  recover ( ) ;  r  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											debug . PrintStack ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											rw . CloseWithError ( fmt . Errorf ( "panic: %v" ,  r ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  req  ReadMultipleReq 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									mr  :=  msgpNewReader ( r . Body ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-07 07:02:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  readMsgpReaderPoolPut ( mr ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  req . DecodeMsg ( mr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										rw . CloseWithError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									mw  :=  msgp . NewWriter ( rw ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									responses  :=  make ( chan  ReadMultipleResp ,  len ( req . Files ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  wg  sync . WaitGroup 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									wg . Add ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									go  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										defer  wg . Done ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  resp  :=  range  responses  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											err  :=  resp . EncodeMsg ( mw ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												rw . CloseWithError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											mw . Flush ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  =  s . getStorage ( ) . ReadMultiple ( r . Context ( ) ,  req ,  responses ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wg . Wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rw . CloseWithError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// globalLocalSetDrives is used for local drive as well as remote REST
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// API caller for other nodes to talk to this node.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Any updates to this must be serialized via globalLocalDrivesMu (locker)
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  globalLocalSetDrives  [ ] [ ] [ ] StorageAPI  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// registerStorageRESTHandlers - register storage rpc router.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  registerStorageRESTHandlers ( router  * mux . Router ,  endpointServerPools  EndpointServerPools ,  gm  * grid . Manager )  {  
						 
					
						
							
								
									
										
										
										
											2023-07-08 22:35:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									h  :=  func ( f  http . HandlerFunc )  http . HandlerFunc  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  collectInternodeStats ( httpTraceHdrs ( f ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-25 07:30:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalLocalDrivesMap  =  make ( map [ string ] StorageAPI ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalLocalSetDrives  =  make ( [ ] [ ] [ ] StorageAPI ,  len ( endpointServerPools ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  pool  :=  range  globalLocalSetDrives  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalLocalSetDrives [ pool ]  =  make ( [ ] [ ] StorageAPI ,  endpointServerPools [ pool ] . SetCount ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  set  :=  range  globalLocalSetDrives [ pool ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											globalLocalSetDrives [ pool ] [ set ]  =  make ( [ ] StorageAPI ,  endpointServerPools [ pool ] . DrivesPerSet ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  serverPool  :=  range  endpointServerPools  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  endpoint  :=  range  serverPool . Endpoints  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ! endpoint . IsLocal  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-19 08:25:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-20 09:42:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-05 03:54:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											server  :=  & storageRESTServer { 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-28 15:02:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												endpoint :  endpoint , 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-20 09:42:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter  :=  router . PathPrefix ( path . Join ( storageRESTPrefix ,  endpoint . Path ) ) . Subrouter ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-07-08 22:35:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodHealth ) . HandlerFunc ( h ( server . HealthHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodAppendFile ) . HandlerFunc ( h ( server . AppendFileHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodCreateFile ) . HandlerFunc ( h ( server . CreateFileHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodDeleteVersions ) . HandlerFunc ( h ( server . DeleteVersionsHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodVerifyFile ) . HandlerFunc ( h ( server . VerifyFileHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodStatInfoFile ) . HandlerFunc ( h ( server . StatInfoFile ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadMultiple ) . HandlerFunc ( h ( server . ReadMultiple ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodCleanAbandoned ) . HandlerFunc ( h ( server . CleanAbandonedDataHandler ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodDeleteBulk ) . HandlerFunc ( h ( server . DeleteBulkHandler ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodPost ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadParts ) . HandlerFunc ( h ( server . ReadPartsHandler ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-26 20:55:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodGet ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadFileStream ) . HandlerFunc ( h ( server . ReadFileStreamHandler ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-29 16:00:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodGet ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadVersion ) . HandlerFunc ( h ( server . ReadVersionHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodGet ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadXL ) . HandlerFunc ( h ( server . ReadXLHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											subrouter . Methods ( http . MethodGet ) . Path ( storageRESTVersionPrefix  +  storageRESTMethodReadFile ) . HandlerFunc ( h ( server . ReadFileHandler ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageListDirRPC . RegisterNoInput ( gm ,  server . ListDirHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageReadAllRPC . Register ( gm ,  server . ReadAllHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 01:54:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageWriteAllRPC . Register ( gm ,  server . WriteAllHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageRenameFileRPC . Register ( gm ,  server . RenameFileHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageRenamePartRPC . Register ( gm ,  server . RenamePartHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageRenameDataRPC . Register ( gm ,  server . RenameDataHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-02 07:42:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageRenameDataInlineRPC . Register ( gm ,  server . RenameDataInlineHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageDeleteFileRPC . Register ( gm ,  server . DeleteFileHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-12 13:50:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageCheckPartsRPC . RegisterNoInput ( gm ,  server . CheckPartsHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-20 06:54:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( storageReadVersionRPC . Register ( gm ,  server . ReadVersionHandlerWS ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageWriteMetadataRPC . Register ( gm ,  server . WriteMetadataHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageUpdateMetadataRPC . Register ( gm ,  server . UpdateMetadataHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageDeleteVersionRPC . Register ( gm ,  server . DeleteVersionHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageReadXLRPC . Register ( gm ,  server . ReadXLHandlerWS ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageNSScannerRPC . RegisterNoInput ( gm ,  server . NSScannerHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageDiskInfoRPC . Register ( gm ,  server . DiskInfoHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( storageStatVolRPC . Register ( gm ,  server . StatVolHandler ,  endpoint . Path ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												perf: websocket grid connectivity for all internode communication (#18461)
This PR adds a WebSocket grid feature that allows servers to communicate via 
a single two-way connection.
There are two request types:
* Single requests, which are `[]byte => ([]byte, error)`. This is for efficient small
  roundtrips with small payloads.
* Streaming requests which are `[]byte, chan []byte => chan []byte (and error)`,
  which allows for different combinations of full two-way streams with an initial payload.
Only a single stream is created between two machines - and there is, as such, no
server/client relation since both sides can initiate and handle requests. Which server
initiates the request is decided deterministically on the server names.
Requests are made through a mux client and server, which handles message
passing, congestion, cancelation, timeouts, etc.
If a connection is lost, all requests are canceled, and the calling server will try
to reconnect. Registered handlers can operate directly on byte 
slices or use a higher-level generics abstraction.
There is no versioning of handlers/clients, and incompatible changes should
be handled by adding new handlers.
The request path can be changed to a new one for any protocol changes.
First, all servers create a "Manager." The manager must know its address 
as well as all remote addresses. This will manage all connections.
To get a connection to any remote, ask the manager to provide it given
the remote address using.
```
func (m *Manager) Connection(host string) *Connection
```
All serverside handlers must also be registered on the manager. This will
make sure that all incoming requests are served. The number of in-flight 
requests and responses must also be given for streaming requests.
The "Connection" returned manages the mux-clients. Requests issued
to the connection will be sent to the remote.
* `func (c *Connection) Request(ctx context.Context, h HandlerID, req []byte) ([]byte, error)`
   performs a single request and returns the result. Any deadline provided on the request is
   forwarded to the server, and canceling the context will make the function return at once.
* `func (c *Connection) NewStream(ctx context.Context, h HandlerID, payload []byte) (st *Stream, err error)`
   will initiate a remote call and send the initial payload.
```Go
// A Stream is a two-way stream.
// All responses *must* be read by the caller.
// If the call is canceled through the context,
//The appropriate error will be returned.
type Stream struct {
	// Responses from the remote server.
	// Channel will be closed after an error or when the remote closes.
	// All responses *must* be read by the caller until either an error is returned or the channel is closed.
	// Canceling the context will cause the context cancellation error to be returned.
	Responses <-chan Response
	// Requests sent to the server.
	// If the handler is defined with 0 incoming capacity this will be nil.
	// Channel *must* be closed to signal the end of the stream.
	// If the request context is canceled, the stream will no longer process requests.
	Requests chan<- []byte
}
type Response struct {
	Msg []byte
	Err error
}
```
There are generic versions of the server/client handlers that allow the use of type
safe implementations for data types that support msgpack marshal/unmarshal.
											 
										 
										
											2023-11-21 09:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . FatalIf ( gm . RegisterStreamingHandler ( grid . HandlerWalkDir ,  grid . StreamHandler { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Subroute :     endpoint . Path , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Handle :       server . WalkDirHandler , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												OutCapacity :  1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} ) ,  "unable to register handler" ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-10 02:03:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											createStorage  :=  func ( endpoint  Endpoint )  bool  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												xl ,  err  :=  newXLStorage ( endpoint ,  false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													// if supported errors don't fail, we proceed to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													// printing message and moving forward.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-03 15:45:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													if  errors . Is ( err ,  errDriveIsRoot )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														err  =  fmt . Errorf ( "major: %v: minor: %v: %w" ,  xl . major ,  xl . minor ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													logFatalErrs ( err ,  endpoint ,  false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												storage  :=  newXLStorageDiskIDCheck ( xl ,  true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												storage . SetDiskID ( xl . diskID ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-24 06:11:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// We do not have to do SetFormatData() since 'xl'
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// already captures formatData cached.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												globalLocalDrivesMu . Lock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												defer  globalLocalDrivesMu . Unlock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-23 07:07:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												globalLocalDrivesMap [ endpoint . String ( ) ]  =  storage 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												globalLocalSetDrives [ endpoint . PoolIdx ] [ endpoint . SetIdx ] [ endpoint . DiskIdx ]  =  storage 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-10 02:03:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  createStorage ( endpoint )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											// Start async goroutine to create storage.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-10 02:03:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											go  func ( endpoint  Endpoint )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												for  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-14 11:27:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													time . Sleep ( 3  *  time . Second ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-10 02:03:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													if  createStorage ( endpoint )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
														return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-10 02:03:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} ( endpoint ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-02 04:01:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-01 16:18:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-10-05 08:44:06 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}