Как уведомить процесс об изменении базы данных SQLite, выполненном в другом процессе? - PullRequest
10 голосов
/ 24 марта 2009

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

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

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

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

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

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

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

Ответы [ 7 ]

5 голосов
/ 24 марта 2009

Реляционная база данных - не лучший выбор для этого.

Почему?

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

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

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

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


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

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

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

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

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


Пожалуйста, уточните "Если редактор выходит из строя во время уведомления, плеер постоянно запутался" в вашем вопросе.

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

3 голосов
/ 14 марта 2014

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

Интерфейс SQLite C

Обратные вызовы уведомлений об изменении данных

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

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

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

Вот немного хакерский обходной путь, который использует C api (из кода Python), чтобы использовать его: https://stackoverflow.com/a/16920926

2 голосов
/ 24 марта 2009

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

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

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

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

2 голосов
/ 24 марта 2009

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

1 голос
/ 24 марта 2009

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

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

1 голос
/ 24 марта 2009

Если он находится на той же машине, самым простым способом было бы иметь именованный канал, «player» с блокировкой read () и «editors», помещающий токен в канал всякий раз, когда они модифицируют DB.

1 голос
/ 24 марта 2009

Редактировать: Я выполняю процессы на одной машине.

На мой взгляд, есть два пути:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...