LINUX.ORG.RU

Как правильнее сделать атомарную запись?

 


0

2

Пилю древовидные комментарии с хранением в монге. Сейчас функция черновая и имеет такой вид:

def add_comment(cid, pid=None, b='testcom'):

    query = {
        '_id':cid,
        'path':pid,
        'created':dt.now(),
        'body':b,
        'depth':0,
        'orderid':1,
        'answers':0
    }

    if pid:
        parent = comments.find_one({"_id":pid})

        if parent['path']:
            query['path']="%s:%s" % ( str(pid), parent['path'] )
        else:
            query['path']=str(pid)

        query['depth']= parent['depth']+1
        query['orderid'] = parent['orderid'] + parent['answers'] + 1

        comments.update({"_id": pid}, {"$inc":{'answers':1}})
        comments.update({"orderid":{"$gte":query['orderid']} }, {"$inc":{'orderid':1}}, multi=True)

    else:
        last_order_id = comments.find({}).sort([('orderid',-1)]).limit(1)
        last_order_id = list(last_order_id)
        if last_order_id:
            query['orderid'] = last_order_id[0]['orderid'] + 1
        else:
            query['orderid'] = 1

    comments.insert(query)

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

Смущают эти три строчки кода выполняющиеся последовательно:

comments.update({"_id": pid}, {"$inc":{'answers':1}})

comments.update({"orderid":{"$gte":query['orderid']} }, {"$inc":{'orderid':1}}, multi=True)

comments.insert(query)

Теоретически, при многопоточном добавлении комментариев при инсерте документа можно сбить последовательность 'orderid' и сделать там повторяющиеся числа. Как такого избежать?

UPD:

Код работает неверно. Правильная версия: https://bitbucket.org/develf/mongo-tree-comments/src/67a6c392c5ed05166df6882f...

★★★★★

Последнее исправление: Siado (всего исправлений: 3)

comments.update({«_id»: pid}, {«$inc»:{'answers':1}})
comments.update({«orderid»:{«$gte»:query['orderid']} }, {«$inc»:{'orderid':1}}, multi=True)

что они делают? что у тебя за orderid?

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

Тут замысел, чтобы все комменты были пронумерованы по порядку (переменная orderid). Первое увеличивает количество ответов на сообщение, это надо для расчета позиции, второе сдвигает нумерацию всех последующих комментариев.

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

инк количества ответов атомарен и потокобезопасен, тут ок.

а позицию лучше не вычисляй явно - просто бери таймстапм с микросекундами + небольшой рандом в довесок. ты получишь уникальные позиции, корректно расположенные во времени по порядку.

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

а позицию лучше не вычисляй явно - просто бери таймстапм с микросекундами + небольшой рандом в довесок. ты получишь уникальные позиции, корректно расположенные во времени по порядку.

Таким способом их не получится правильно расположить в ветке. А уж тем более добавить новый комментарий посередине ветки.

Siado ★★★★★
() автор топика
Последнее исправление: Siado (всего исправлений: 1)
Ответ на: комментарий от VladimirMalyk

инк количества ответов атомарен и потокобезопасен, тут ок.

Количество ответов - атомарно, сдвиг позиций тоже атомарен, инсерт тоже атомарен. Суть в том, что эти три функции не могут выполняться атомарно последовательно и при многопоточности между ними можно умудриться сделать лишнюю запись.

Siado ★★★★★
() автор топика
Ответ на: комментарий от VladimirMalyk

Я видел эту ссылку. Там нет ответа на вопрос из топика.

Siado ★★★★★
() автор топика
Последнее исправление: Siado (всего исправлений: 1)
Ответ на: комментарий от Siado

Количество ответов - атомарно, сдвиг позиций тоже атомарен, инсерт тоже атомарен.

я прост не до конца понимаю зачем имплементить все именно так. такое решение атомарным на монге не получится. findAndModify можно попробовать, но не взлетит на такой архитектуре

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

я прост не до конца понимаю зачем имплементить все именно так.

Чтобы упростить запросы к бд.

findAndModify можно попробовать, но не взлетит на такой архитектуре

Думал, как findAndModify приспособить, но оно похоже вообще не взлетит по применению к древовидным комментам, не только к этой архитектуре.

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

ну, строго атомарным дерево комменто будет только если все дерево умещается в один документ, что кста и советуют ребята из 10gen. тогда и findAndModify тоже отработает атомарно.

остальные варианты будут однозначно не атомарными.

хороший тон, когда запись не требует доп запросов (напр как у тебя «всего комментов» и проч) а сразу пишет консистентные данные (мой костыль с нумерацией по времени).

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

ну, строго атомарным дерево комменто будет только если все дерево умещается в один документ, что кста и советуют ребята из 10gen. тогда и findAndModify тоже отработает атомарно.

Не ну можно конечно id'ы всех комментариев хранить в одном документе с помощью списков. Но имхо это изврат.

а сразу пишет консистентные данные (мой костыль с нумерацией по времени).

Ну вот объясни, как ты своим костылем добавишь коммент сюда:

2013-10-29 20:59:09.391000 - a
 2013-10-29 20:59:09.393000 - b
  2013-10-29 20:59:09.434000 - m
  _ сюда.
   2013-10-29 20:59:09.438000 - n
    2013-10-29 20:59:09.442000 - o
  2013-10-29 20:59:09.485000 - t
 2013-10-29 20:59:09.396000 - c
 2013-10-29 20:59:09.400000 - d
  2013-10-29 20:59:09.404000 - e
   2013-10-29 20:59:09.408000 - f
    2013-10-29 20:59:09.412000 - g
     2013-10-29 20:59:09.416000 - h
     2013-10-29 20:59:09.446000 - p
   2013-10-29 20:59:09.420000 - i
   2013-10-29 20:59:09.424000 - j
    2013-10-29 20:59:09.455000 - r
 2013-10-29 20:59:09.428000 - k
2013-10-29 20:59:09.432000 - l
 2013-10-29 20:59:09.451000 - q
2013-10-29 20:59:09.483000 - s

А потом приведешь дерево комментов к такому виду?

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

2013-10-29 20:59:09.393000 - b
2013-10-29 20:59:09.434000 - m
_ сюда. - сюда ты его не добавишь, потому что он был позже чем 20:59:09.438000
2013-10-29 20:59:09.438000 - n
2013-10-29 20:59:09.442000 - o
_ он добавится сюда, ниже предыдушего 20:59:09.438000 коммента, дальше во времени
2013-10-29 20:59:09.485000 - t

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

дерево поплыло, сорр. сейчас убегаю, позже смогу продолжить разговор

VladimirMalyk ★★★★★
()

Я бы сделал сортировку для HTML по времени создания. Тогда order-id не нужен. Собственно, от времени создания тоже можно отказаться, ибо оно по умолчанию содержится в _id. Но если тебе кажется, что такой способ оверхед - делай транзакции.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Я бы сделал сортировку для HTML по времени создания.

Чем это будет отличаться от организации комментов на лоре? :)

ибо оно по умолчанию содержится в _id.

А как потом выборку по датам делать?

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

Мое дело предложить :)

Также можно попробовать решение со списком коментариев, 16 мб хватит всем :)

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Также можно попробовать решение со списком коментариев, 16 мб хватит всем :)

16 мб должно хватить, даже РФВС и прочие лоротемы столько не набирали. Но что-то мне подсказывает так будет крайне неудобно делать запросы и приведение к сортированному виду придется перекладывать на код.

И почему как на ЛОРе? Тебе нужно знать лишь на каком уровне находится парент коммент ( у тебя это в depth строится).

Тогда придется свистоперделки навешивать чтобы этот коммент расположить не только по уровню, но и в правильной ветке.

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

он добавится в ноду «438000 - n», визуально будет ниже «442000 - o» по простыне, но выше по уровню вложенности. как на хабрах и опеннетах

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

Не будет, т.к. одного времени не достаточно, если коммент ниже будет более старой датой - то оно разместится ниже его. Еще надо на основе чего-то разместить в правильной ветке.

Siado ★★★★★
() автор топика

С древовидным хранением будут 2 трабла:

1. Очень гиморно делать пагинацию на больших тредах
2. Теоретически возможна коллизия, если 2 человека сделают комментарий одновременно. В принципе на это можно забить.

Если плоский вид не нужен, и дерево всегда показывается на одной странице, то проще всего сделать плоский список + materialized path http://docs.mongodb.org/manual/tutorial/model-tree-structures-with-materializ... , по которому сортировать посты. Вложенная сортировка автоматически получится по порядку добавления.

Если вам надо отображать дерево, если не значит, что структура обязана быть древовидной. Хватит плоского списка с правильным порядком + уровня вложенности.

Vit ★★★★★
()
Ответ на: комментарий от Vit

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

Тогда придется при каждом запросе страницы вызывать рекурсивную фукнцию обхода, которая будет рассортировывать коменты в правильном порядке.

Если вам надо отображать дерево, если не значит, что структура обязана быть древовидной. Хватит плоского списка с правильным порядком + уровня вложенности.

По сути у меня так и получилось - высчитывается порядок предоставления комментариев и их отступ.

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

Рекурсии на плоском списке не будет. Там обычная сортировка по строкам (matherialized paths). Это можно прямо в запросе задать.

Vit ★★★★★
()
Ответ на: комментарий от Siado

Еще надо на основе чего-то разместить в правильной ветке.

пиши в него дату «родительского» коммента - корня ветки в который идет ответ

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

а вообще посмотри книгу MongoDB Applied Design Patterns by Rick Copeland

Полезная книженция, спасибо за наводку

Siado ★★★★★
() автор топика
Ответ на: комментарий от VladimirMalyk

db.comments.update({_id: уник_коммента}, {parent: уник_родителя, text: 'привет мир'}, {upsert: true}) или как то так

Да с добавлением проблем нет любыми способами. Отобразить-то потом это как?

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

если предположить, что у всех комментов есть какойнить тред_йд, то просто выбираешь все комменты этого треда и сортируешь по дате.

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

или ты хочешь такую выборку, чтобы сразу получить готовую структуру данных, которую надо просто обернуть тегами или отпулить в джейсон?

VladimirMalyk ★★★★★
()
Последнее исправление: VladimirMalyk (всего исправлений: 1)
Ответ на: комментарий от VladimirMalyk

или ты хочешь такую выборку, чтобы сразу получить готовую структуру данных, которую надо просто обернуть тегами или отпулить в джейсон?

Именно такое и хочу. Снизить нагрузку при отрисовке комментариев.

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

ну тогда да, как советовал оратор выше: http://docs.mongodb.org/manual/tutorial/model-tree-structures-with-materializ...

где path это цепочка тамстампов.

db.comments.update({_id: уник_коммента}, {path: цепочка_из_родительских_уников, text: 'привет мир'}, {upsert: true})

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

И конечно же к этому отдельную функцию сортировки в правильное дерево комментариев да? =)

Siado ★★★★★
() автор топика
Ответ на: комментарий от Siado

You can query to retrieve the whole tree, sorting by the field path:

db.categories.find().sort( { path: 1 } )

VladimirMalyk ★★★★★
()
Ответ на: комментарий от Siado

и если вместо таймстампа использовать mongoid (как советовали выше) - то оно как текст норм отсортируется. дату коммента отдельно держать

VladimirMalyk ★★★★★
()
Ответ на: комментарий от VladimirMalyk

Да не получится так. Пожалуй единственный способ вытянуть из бд одним запросом - это добавить что-то типа избыточной нумерации. Как у меня. Но здесь есть вероятность того, что при добавлении собъется нумерация и тога придется строить её заного.

Siado ★★★★★
() автор топика
Последнее исправление: Siado (всего исправлений: 2)
Ответ на: комментарий от VladimirMalyk

О блин, это похоже были дни тупняка. Действительно как текст норм отсортировывается =)

Siado ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.