Я использую Firestore в режиме хранилища данных. Я не использую клиентскую библиотеку, предоставленную Google или кем-либо еще, и не общаюсь с Datastore напрямую через сгенерированный (Google) из библиотеки proto grpc (...

0
QuestionAndAnswer 19 Янв 2021 в 11:08

1 ответ

Лучший ответ

Хранилище данных накладывает ограничения на то, что может быть выполнено внутри одной транзакции. Обычно на одновременную транзакцию / модификацию ответят, когда возникает конфликт фиксации. Вы можете воспроизвести это, запустив две транзакции, которые записывают в один и тот же документ, зафиксировать и увидеть ожидаемое поведение.

Документация:

Когда две или несколько транзакций одновременно пытаются изменить сущности в одной или нескольких общих группах сущностей, только первая транзакция, зафиксировавшая свои изменения, может быть успешной; все остальные потерпят неудачу при фиксации. Из-за этой конструкции использование групп сущностей ограничивает количество одновременных операций записи, которые вы можете выполнять для любой сущности в группах. Когда транзакция начинается, Datastore использует оптимистичный контроль параллелизма, проверяя время последнего обновления для групп сущностей, используемых в транзакции. После фиксации транзакции для групп сущностей Datastore снова проверяет время последнего обновления для групп сущностей, используемых в транзакции. Если он изменился с момента первоначальной проверки, выдается исключение.

Лучшим способом было бы быстро воспроизвести его и увидеть точное поведение. Возникает вопрос, не удастся ли выполнить всю операцию фиксации при конфликте версий в каком-либо объекте?

Да.

Обертка автоматически повторит вашу транзакцию. Библиотека транзакций хранилища данных Golang должна предоставить больше информации о том, как она ведет себя. Для получения дополнительной информации см. {{X1 }}, показанный ниже, и посмотрите, как он оценивает транзакцию.

func (c *Client) RunInTransaction(ctx context.Context, f func(tx *Transaction) error, opts ...TransactionOption) (cmt *Commit, err error) {
        ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.RunInTransaction")
        defer func() { trace.EndSpan(ctx, err) }()
     
        settings := newTransactionSettings(opts)
        for n := 0; n < settings.attempts; n++ {
     tx, err := c.newTransaction(ctx, settings)
     if err != nil {
     return nil, err
     }
     if err := f(tx); err != nil {
     _ = tx.Rollback()
     return nil, err
     }
     if cmt, err := tx.Commit(); err != ErrConcurrentTransaction {
     return cmt, err
     }
     // Pass this transaction's ID to the retry transaction to preserve
     // transaction priority.
     if !settings.readOnly {
     settings.prevID = tx.id
     }
        }
        return nil, ErrConcurrentTransaction
    }
1
Andrew 22 Янв 2021 в 13:53