> Hi,
> I have two processes connecting to a database. Both can modify database.
When
> some process modify database, I want the other to be notified (so, it can
> reload data).
> Currently, I use unix sockets, so a process can notify all listener
process
> that something has changed. But I wonder if there's a better way to
achieve
> that.
> I've tried to a create a custom function (with sqlite3_create_function),
and
> use triggers. But unfortunately, my trigger was executed for the modifying
> process.
> So, is there a sqlitish way to have process notifications, or should I
stick
> to using unix sockets to tell other processes something has changed in the
> database.
> I'm using C++ language (C api for sqlite)
>
> regards
> arno
Howdy, Arno.

I'm a long-time lurker on this list, but until now I haven't had much to
contribute.

However... on this topic, I might finally have something to offer.

About a year ago, I was working on this very problem, and have a working
prototype of an SQLite library with a cross-process asynchronous update
notification mechanism.

When we originally encountered this problem, we tried to characterize it
as best we could and then considered a few alternative solutions
(which we numbered Option #1 through Option #5 in our documents). One of
our (formerly) internal engineering documents includes discussion of this
subject and might provide some useful context; see

http://www.innovision.com/techdocs/sqlite/PersistentDataSharingAndConcurrenc
yControl.pdf

Ultimately, we developed prototypes (i.e., enhanced SQLite libraries)
for a couple of the options (first, Option #5, and later, Option #3).

Another (formerly) internal document further expands on the requirements we
wanted to satisfy and how we went about solving (at least sufficient for a
prototype) the problem; see

http://www.innovision.com/techdocs/sqlite/SQLiteAsyncDatabaseChange.pdf

I'll warn you that the document I just referenced probably needs to be
updated to be a more accurate reflection of our latest solution to the
problem (which is now based on Option #3 rather than Option #5).

>From the perspective of a programmer, what they're seeing with the
enhanced SQLite library is a new SQLite API function:

/*
** The sqlite3_async_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever the database has been modified in any way.
**
** The monitoring of the database occurs in a separate thread (one thread
** per monitored connection) from the thread that invoked
** sqlite3_async_update_hook().  When a database modification is detected,
** the callback function is called from the monitoring thread.  Thus,
** some thread-level synchronization mechanism (e.g., appropriate thread
** safety mode and database locking) should be used as appropriate.
**
** If the async update hook callback function pointer is NULL then the no
** update callbacks are made.
**
** If an async update hook callback function has been registered with a
** database connection at the time it is closed, the callback function
** will automatically be unregistered as part of the connection close
** operation.
**
** The second argument is a pointer to the function to invoke when the
** database is modified.
** The first argument to the callback is a copy of the third argument
** to sqlite3_async_update_hook().
** The second callback argument is a pointer to the database name.
**
** If another function was previously registered, its pArg value
** is returned.  Otherwise NULL is returned.
*/
void *sqlite3_async_update_hook(
  sqlite3*,
  void(*)(void *, const char *),
  void*
);


When I was working on the Option #5 prototype; I created a video demo.
If I did it again for Option #3, it probably wouldn't be much different.
The demo shows the mechanism working both within a single process as
well as across two processes (a Lua-based GUI prototype app, and the
sqlite3.exe command line utility, each linked against the enhanced
SQLite library). (The Lua aspect is irrelevant here; LuaSQL just happened
to be another thing we wanted to evaluate in this prototype).

The video demo is available in two formats an AVI (codec available at
http://www.techsmith.com/download/codecs.asp):

http://www.innovision.com/techdocs/sqlite/SQLiteAsyncDatabaseChangeExample3.
avi

and a lower-quality MPEG:

http://www.innovision.com/techdocs/sqlite/SQLiteAsyncDatabaseChangeExample3.
mp4


Now... I've been away from this for at least half a year, but here are
some of my thoughts at this point:

1. It appears that our desire to have cross-process update notification
is shared by others, so maybe it's time to have the SQLite community dig
into this issue more and see if we can arrive at a mutually beneficial
solution.

2. Any solution involving the database writer/changer to take any
explicit action (e.g. signaling, etc.) to notify other processes
possibly using that database file that it has changed is likely to
have undesirable vulnerabilities (change can occur that will go
undetected, etc.) Consider: (a) file-level copy operations,
(b) changes by other tools that don't "follow the rules," etc.

3. As I recall, there were a number of advantages to going with a more
"built into SQLite" approach. Among them (a few that I remember right
now):
- By building it into SQLite, it is more likely to work consistently and
robustly across all SQLite-based apps and tools and on all platforms,
even if the apps and tools were developed by different
people/organizations.
- There are certain control points in the lower levels of SQLite (e.g.,
the b-tree and pager layers) that make excellent places to wedge in
change notification mechanisms. In the absence of using such control
points, notification mechanisms are harder to implement and tend to
suffer from inefficiencies (e.g., doing certain notification-related
things when a particular database file is known to be locked and just
changed can be much more optimal than alternatives).
- Simplicity from the perspective of the SQLite library user.
- Who wants to keep re-inventing this wheel?

4. An interesting point to ponder as you're evaluating alternative
approaches to this problem: What layer of software really knows what
files are involved in a database connection over time? I'd claim
that it's SQLite (not the app layer above it). Take, for example, an
application that opens an SQLite database connection and then
executes arbitrary (e.g., from a console or an input file) SQL
commands against it. Some of those commands might be
ATTACH DATABASE or DETACH DATABASE commands. So... the set of files
that need to be monitored for change is itself changing. Where is
that information most readily available? Yup... at the SQLite level.

5. It would be possible to implement a good, high quality cross-process
notification mechanism without building it directly into SQLite if
SQLite were first enhanced with some new callback hooks at just the right
places (I won't elaborate on these further without first reviewing
our code to see where those hooks would need to be). Some SQLite VFS
extensions could also help put platform-dependent code where it belongs
and minimize the surface area of code for anyone wanting to port SQLite
(along with the cross-process notification mechanism) to a new platform.

6. The change granularity is a significant issue. It's not too hard or
expensive to provide change notification on a database file level.
Getting more fine grained, though, becomes much more difficult. While
it would be great to get table (or even row-level) cross-process
change notification, it is difficult to see how this could be done
efficiently without significant implementation done inside the
bowels of SQLite. Database-level granularity is enough to at least
get the ball rolling; additional mechanisms (e.g., trigger-based
change logging to a journal table or some such) can always be layered
on top of this if finer grain is needed. Of course, such finer-grained
features *could* be built into SQLite at a later date.

7. From the perspective of a user of the SQLite library, it's hard to
beat the simplicity of a function like what we did:

void * sqlite3_async_update_hook(sqlite3 *db,
  void(*)(void *context, char const *dbname), void *context);

8. I'd really like to either get this functionality built into SQLite
*or* go the opposite direction and get more-or-less the same API-level
functionality, but with the notification mechanism source code as
decoupled as much as possible from the SQLite source code. It's just
not desirable for us to maintain the customized-SQLite-source-code
solution we're using right now.

--
Ed Scherer
Innovision Corporation



_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to