Модуль Golang MGO блокирует или разблокирует объекты Go? - PullRequest
0 голосов
/ 01 июня 2018

Я пытаюсь понять, блокирует ли Монго объекты Go.

Первая функция прекрасно работает с кодировщиком json, однако вторая функция не работает fatal error: sync: Unlock of unlocked RWMutex.Это потому, что mongo.Find уже пытается заблокировать / разблокировать объект состояния?Нужно ли мне участвовать в гонках за свои объекты, или MGO позаботится об этом?Я попытался прочитать исходный код, но не смог прийти к выводу.

Любой был бы очень признателен!

import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"io"
"sync"
"encoding/json"
)

type ApplicationState struct {
    FileStates map[string]FileState     `json:"fileStates" bson:"fileStates"` 
    lock       sync.RWMutex             `json:"-" bson:"-"`
}

func (state *ApplicationState) ReadState(reader io.Reader) error {
    state.lock.Lock()
    defer state.lock.Unlock()
    return json.NewDecoder(reader).Decode(state)}

func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
    state.lock.Lock()
    defer state.lock.Unlock()
    return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)}

Примечание: чтобы проверить его, вы можете просто заменить Filestateполе со строкой карты.

1 Ответ

0 голосов
/ 01 июня 2018

Во-первых, бросьте gopkg.in/mgo.v2, это устаревшее, необслуживаемое.Вместо этого используйте форк, поддерживаемый сообществом: github.com/globalsign/mgo.

Далее вы должны сначала прочитать публичную документацию, пакетную документацию и только «вернуться» к чтению исходного кода, чтобы очистить такие вещи, еслидокументация не предлагает ответы.Но делать выводы из источника всегда опасно, так как реализация может измениться в любое время, гарантируется только то, что задокументировано.Документация mgo.Session гласит:

Все методы сеанса безопасны для параллелизма и могут вызываться из нескольких программ.

Это всегарантия у вас есть, и все, от чего вы должны зависеть.Использование методов mgo.Collection может быть или не быть безопасным для одновременного использования, поэтому не делайте этого.При необходимости всегда получайте «новую» коллекцию из сеанса, поскольку к ней можно безопасно обращаться из нескольких программ.

А теперь перейдем к вашей актуальной проблеме.

Ваша ApplicationState structТип содержит блокировку (sync.RWMutex), и вы отменяете маршалирование результата запроса в то же значение ApplicationState, которое содержит блокировку:

func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
    state.lock.Lock()
    defer state.lock.Unlock()
    return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)
}

Это красный флаг!Не делай этого!Немаршалинг в значение может очистить любые поля, включая блокировку!

Да, вы можете сказать, что это неэкспортированное поле, поэтому пакет mgo не должен / не может его изменить.Это верно, но пакет mgo может решить создать новое значение ApplicationState для разархивирования, и новое значение может быть назначено значению, указанному переданным указателем (state).

Если это произойдет, у вновь созданного ApplicationState будет поле lock, равное его нулевому значению, которое является разблокированным мьютексом.И как только это произойдет, последующая разблокировка, очевидно, не удастся (паника).

Решение?Переместите блокировки за пределы значений структуры, которые вы намереваетесь сериализовать / десериализовать.Или, по крайней мере, не ожидайте передачи состояния блокировки вместе с другими полями.

...