fix: objectManager implementation avoid racy goroutines (#3392)

fixes #3391
This commit is contained in:
Harshavardhana
2024-06-25 08:50:31 -07:00
committed by GitHub
parent a89d7ec0ea
commit 22176f4e0f

View File

@@ -35,9 +35,11 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
defer func() {
// We close socket at the end of requests
wsc.conn.close()
cancelContexts.Range(func(_, value interface{}) bool {
cancelContexts.Range(func(key, value interface{}) bool {
cancelFunc := value.(context.CancelFunc)
cancelFunc()
cancelContexts.Delete(key)
return true
})
}()
@@ -55,6 +57,7 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
// Read goroutine
go func() {
defer close(writeChannel)
for {
select {
case <-done:
@@ -72,10 +75,9 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
// We get request data & review information
var messageRequest ObjectsRequest
err := json.Unmarshal(message, &messageRequest)
if err != nil {
LogInfo("Error on message request unmarshal")
return
if err := json.Unmarshal(message, &messageRequest); err != nil {
LogInfo("Error on message request unmarshal", err)
continue
}
// new message, new context
@@ -84,6 +86,21 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
// We store the cancel func associated with this request
cancelContexts.Store(messageRequest.RequestID, cancel)
switch messageRequest.Mode {
case "objects", "rewind":
// cancel all previous open objects requests for listing
cancelContexts.Range(func(key, value interface{}) bool {
rid := key.(int64)
if rid < messageRequest.RequestID {
cancelFunc := value.(context.CancelFunc)
cancelFunc()
cancelContexts.Delete(key)
}
return true
})
}
const itemsPerBatch = 1000
switch messageRequest.Mode {
case "close":
@@ -95,18 +112,7 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
cancelContexts.Delete(messageRequest.RequestID)
}
case "objects":
// cancel all previous open objects requests for listing
cancelContexts.Range(func(key, value interface{}) bool {
rid := key.(int64)
if rid < messageRequest.RequestID {
cancelFunc := value.(context.CancelFunc)
cancelFunc()
}
return true
})
// start listing and writing to web socket
go func() {
objectRqConfigs, err := getObjectsOptionsFromReq(messageRequest)
if err != nil {
LogInfo(fmt.Sprintf("Error during Objects OptionsParse %s", err.Error()))
@@ -120,12 +126,9 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
return
}
var buffer []ObjectResponse
for lsObj := range startObjectsListing(ctx, wsc.client, objectRqConfigs) {
if _, ok := cancelContexts.Load(messageRequest.RequestID); !ok {
return
}
if lsObj.Err != nil {
sendWSResponse(WSResponse{
RequestID: messageRequest.RequestID,
@@ -166,22 +169,13 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
RequestEnd: true,
})
// remove the cancellation context
// if we have that request id, cancel it
if cancelFunc, ok := cancelContexts.Load(messageRequest.RequestID); ok {
cancelFunc.(context.CancelFunc)()
cancelContexts.Delete(messageRequest.RequestID)
}()
case "rewind":
// cancel all previous open objects requests for listing
cancelContexts.Range(func(key, value interface{}) bool {
rid := key.(int64)
if rid < messageRequest.RequestID {
cancelFunc := value.(context.CancelFunc)
cancelFunc()
}
return true
})
case "rewind":
// start listing and writing to web socket
go func() {
objectRqConfigs, err := getObjectsOptionsFromReq(messageRequest)
if err != nil {
LogInfo(fmt.Sprintf("Error during Objects OptionsParse %s", err.Error()))
@@ -206,7 +200,6 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
BucketName: messageRequest.BucketName,
})
cancel()
return
}
@@ -259,9 +252,11 @@ func (wsc *wsMinioClient) objectManager(session *models.Principal) {
RequestEnd: true,
})
// remove the cancellation context
// if we have that request id, cancel it
if cancelFunc, ok := cancelContexts.Load(messageRequest.RequestID); ok {
cancelFunc.(context.CancelFunc)()
cancelContexts.Delete(messageRequest.RequestID)
}()
}
}
}
}