Во-первых, бросьте 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
, равное его нулевому значению, которое является разблокированным мьютексом.И как только это произойдет, последующая разблокировка, очевидно, не удастся (паника).
Решение?Переместите блокировки за пределы значений структуры, которые вы намереваетесь сериализовать / десериализовать.Или, по крайней мере, не ожидайте передачи состояния блокировки вместе с другими полями.