Rethinkdb атомарное извлечение и обновление

Скажем, у меня есть следующая структура данных:

{ "name": "i1", "time": 1, "status": 1}
{ "name": "i2", "time": 2, "status": 1}
{ "name": "i3", "time": 3, "status": 1}
{ "name": "i4", "time": 4, "status": 2}

Мне нужно получить элемент с наибольшим временем и «статус» = 1. Затем обновить его «статус» до 2, все это атомарно, чтобы один и тот же элемент не мог быть получен другим потребителем в то же время.

Возможно ли это с rethinkdb?


person sanyi    schedule 31.03.2015    source источник


Ответы (1)


Поскольку атомарность в RethinkDB гарантируется только на уровне отдельных документов, это возможно лишь частично.

Вы можете сделать что-то вроде этого:

r.table(...)
  .orderBy(index=r.desc("time"))
  .filter({status: 1})
  .limit(1)
  .update(r.branch(r.row["status"] == 1, {status: 2}, {}), return_changes=True)

Все внутри update будет применяться атомарно. Таким образом, если статус записи уже был установлен другим клиентом на 2, запрос вернет {без изменений: 1}, и вы можете запустить его снова, пока он не выполнит успешное обновление.

Однако это не гарантирует, что во время выполнения обновления выбранный документ по-прежнему будет документом с наибольшим временем. Другой клиент мог бы вставить новый документ с большим временем во время выполнения этого запроса, что заставило бы запрос обновить статус единственного на тот момент второго по величине документа до 2.

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

person Daniel Mewes    schedule 31.03.2015
comment
Благодарю вас! Поиск неизменного делает свое дело. В моем случае достаточно выбрать подход с наибольшим временем и наилучшими усилиями. Однако, по крайней мере, в python выполнение обновления на limit(1) вызовет TypeError: 'r.row' не вызывается, вместо этого используйте 'r.row[...]'. - person sanyi; 01.04.2015
comment
Извините, в моем запросе использовался синтаксис JavaScript. Я собираюсь отредактировать его. - person Daniel Mewes; 01.04.2015