Как я могу уведомить процесс изменения базы данных SQLite в другом процессе?

Скажем, у меня есть два или несколько процессов, связанных с базой данных SQLite - процесс "игрока" и многие "редакционные" процессы.

Процесс "player" читает базу данных и обновляет представление - в моем случае это будет форма волны, смешанная с звуковой картой, в зависимости от событий, хранящихся в базе данных.

Процесс "редактора" - это любой редактор для этой базы данных: он постоянно изменяет базу данных.

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

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

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

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

Ответ 1

Реляционная база данных не является для вас лучшим выбором.

Почему?

Вы хотите, чтобы все ваши редакторы передавали вам изменения.

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

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

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


Лучший дизайн - это сервер, который принимает сообщения от редакторов, сохраняет их и уведомляет игрока. Этот сервер не является ни редактором, ни игроком, а просто брокером, который гарантирует, что все сообщения будут обработаны. Он принимает соединения от редакторов и игроков. Он управляет базой данных.

Существует две реализации. Сервер - игрок. Сервер отдельно от игрока. Конструкция сервера не изменяется - только протокол. Когда сервер является игроком, сервер напрямую вызывает объекты игрока. Когда сервер отдельно от проигрывателя, сервер записывается в гнездо плеера.

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

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

Если ваш трафик сообщений является достаточно небольшим, чтобы сетевая латентность не была проблемой, редактор отправляет все данные на сервер/плеер. Если трафик сообщений слишком велик, редактор записывает в базу данных и отправляет сообщение только с базой данных FK на сервер/плеер.


Просьба пояснить: "Если редактор сбой при уведомлении, игрок постоянно перепутался" в вашем вопросе.

Это звучит как плохой дизайн для службы плеера. Он не может быть "постоянно испорчен", если он не получает статус от разных редакторов. Если он получает состояние от редакторов (но, например, пытается зеркально отразить это состояние), вы должны рассмотреть дизайн, в котором игрок просто получает состояние из редактора и не может "постоянно перепутаться".

Ответ 2

В SQLite есть функция update_hook, которая делает то, что вы хотите.

Интерфейс SQLite C

Обратные вызовы с изменениями данных

void *sqlite3_update_hook(
    sqlite3*,
    void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    void*
);

Интерфейс sqlite3_update_hook() регистрирует функцию обратного вызова с соединение с базой данных, идентифицированное с помощью первого аргумента, вызываемого всякий раз, когда строка обновляется, вставлена ​​или удалена в таблице rowid. Любые callback, установленный предыдущим вызовом этой функции для той же базы данных соединение отменено.

К сожалению, он не раскрывается модулем sqlite Python...

Вот несколько хакерский обходной путь, который копается в C api (из кода Python), чтобы использовать его: fooobar.com/questions/507627/...

Ответ 3

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

Ответ 4

Я думаю, что в этом случае я бы сделал процесс управления чтением/записью базы данных.

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

Этот процесс может затем уведомить игрока об изменении базы данных. Игрок, когда он хочет получить некоторые данные, должен сделать запрос данных, которые он хочет обработать, управляя базой данных. (Или процесс db сообщает ему, что ему нужно, когда он уведомляет об изменении, поэтому запрос от игрока не нужен)

Выполнение этого будет иметь преимущество в том, что только один процесс получает доступ к базе данных SQLite, поэтому в базе данных нет проблем с блокировкой или concurrency.

Ответ 5

Изменить: Я обрабатываю процессы на одной машине.

По-моему, есть два способа:

  • Опрос (как вы упомянули), но сохраните его до одного значения (например, таблицы, которая просто сохраняет LastUpdateTime для других таблиц)

  • Используйте любую межпроцессную связь, доступную на целевой платформе. Это могут быть события в Windows (например, в С# (я не знаю в Python), ManualResetEvent, AutoResetEvent или Mutex, если вы хотите пожертвовать нитью официанта в каждом процессе) или Signals в Linux.

Ответ 6

Если это на одной машине, самым простым способом было бы иметь именованный канал, "плеер" с блокировкой read() и "редакторы", помещая токен в канал всякий раз, когда они изменяют БД.

Ответ 7

Сколько процессов редактора (почему обрабатывается?) и как часто вы ожидаете обновления? Это не похоже на хороший дизайн, особенно не учитывая, что sqlite действительно не является слишком счастливым в отношении нескольких одновременных доступов к базе данных.

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