add version numbers: these allow multi-user updates to be distinguished

properly.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3670 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2001-02-19 08:38:54 +00:00
parent c9a40649ec
commit 9f09ab589d
8 changed files with 761 additions and 455 deletions

View File

@ -2,7 +2,7 @@
# Build the postgres backend as its own loadable shared object. # Build the postgres backend as its own loadable shared object.
lib_LTLIBRARIES = libgnc_postgres.la lib_LTLIBRARIES = libgnc_postgres.la
libgnc_postgres_la_LDFLAGS = -version-info 5:3:5 libgnc_postgres_la_LDFLAGS = -version-info 6:0:6
libgnc_postgres_la_SOURCES = \ libgnc_postgres_la_SOURCES = \

File diff suppressed because it is too large Load Diff

View File

@ -50,12 +50,6 @@ To Be Done
---------- ----------
Core bugs/features that still need work: Core bugs/features that still need work:
-- bug/feature: the 'save as' semantics are ... unexpected, if
the database already exists and has data in it ...
-- bug: group sync doesn't pull in newer data from the db ...
(related to the 'save as' above)
-- allow user to enter URL in GUI dialog, get GUI to remember the URL -- allow user to enter URL in GUI dialog, get GUI to remember the URL
-- Implement GUI to ask user for username/password to log onto the -- Implement GUI to ask user for username/password to log onto the
@ -65,21 +59,47 @@ Core bugs/features that still need work:
mods to gnc-book to keep it happy about lock files & such. mods to gnc-book to keep it happy about lock files & such.
(coord with rlb on gnc-book redesign) (coord with rlb on gnc-book redesign)
-- review (actually, design & architect) the communications error
handling policy. For example, CopyToEngine() will leave
the backend in a disabled state if a communication error occurs;
there will be other debiliting conditions if the backend disappears,
leaving the engine in a possibly confused state.
-- during sync, detect and report conflicting edits to accounts
and transactions. See the notes for pgendSync() for details
as to what this is about. For the first pass, this is not a
serious issue; its a 'nice to have' thing.
To Be Done, Part II To Be Done, Part II
------------------- -------------------
This list only affects the multi-user and advanced/optional features. This list only affects the multi-user and advanced/optional features.
-- saving as single-user, then re-opening in multi-user mains missing
checkpoints, and thus no balances.
-- implement account commit edit (actually, the check&rollback part) -- checkpoint ending balance is showing up as starting balance
(need to check the account version number beofer the commit happens)
-- use version numbers for accounts, commodities, splits & transactions, -- transaction rollbck is 'incorrect'; sort of ?? since we should
as this will provide a far more efficient 'compare' for roll back to what's in the db, and not the old stored transaction ...
user changes. but the way the register works, it hides this problem ...
-- store account balances in database. This will be tricky ...
-- split query gets hard ...
-- use postgres aggregates ??
-- provide support for more query types in gncquery.c -- provide support for more query types in gncquery.c
-- implement account rollback (i.e. of other user has modified the
account, we need to do something to merge thier work into ours...)
-- fix caching in the face of lost contact to the backend. If the
backend can't contact its server, then we should just save up caches,
and then when contact with backend re-established, we should spit
them out. The pgendSync routine should more or less dothe trick;
note, however, that the file format needs to save the version number
...
-- Implement logging history in the SQL server. i.e. save the old -- Implement logging history in the SQL server. i.e. save the old
copies of stuff in log tables. Make the username part of the copies of stuff in log tables. Make the username part of the
logging scheme. logging scheme.
@ -93,40 +113,32 @@ This list only affects the multi-user and advanced/optional features.
tries to write to something they're not allowed to write to, tries to write to something they're not allowed to write to,
then they should be bounced back. then they should be bounced back.
-- versioning verification in backend. The desired semantic for updates -- Review versioning verification in backend. The desired semantic for
should be like CVS: multiple nearly-simultaneous writers are allowed; updates should be like CVS: multiple nearly-simultaneous writers
however, only one wins, and others are kicked back. The losers know are allowed; however, only one wins, and others are kicked back.
themselves because they are trying to update info of the wrong The losers know themselves because they are trying to update info
version. But right now, version is not done everywhere, nor is it of the wrong version.
done uniformly: -- pgend_transaction_commit does it correctly; but the gui doesn't
-- pgend_transaction_commit does it correctly. report a rollback.
-- pgTransactionSync does not, it clobbers. -- pgTransactionSync() is broken, but its not used anywher.
-- pgend_account_commit clobbers. -- pgend_account_commit checks version but doesn't rollback.
-- pgendAccountGroupSync is unfinished. (nor does the dui report a rollback.
-- pgendSync does the right thing, except that it doesn't
detect any version conflicts, nor does it notify the user
of such conflicts.
I'm not sure how critical this all is; with a small number of users I'm not sure how critical this all is; with a small number of users
it shouldn't be a problem. With a huge number of users, each editing it shouldn't be a problem. With a huge number of users, each editing
the same transaction (unlikely!?) then there is risk of clobbered the same transaction (unlikely!?) then there is risk of clobbered
data, but so what? data, but so what? ersioning is at least partly a people-management
problem. Anyway, what's there now should be pretty good & should
-- fix rollback bug in GUI. If backend tells engine to rollback, work for now. Except its mostly untested.
(e.g. on a new transaction), the GUI still shows traces, instead
of kicking back.
This is a symptom of a lack of kick-back detection in GUI.
-- finish implementing pgendAccountGroupSync
-- store account balances in database. This will be tricky ...
-- split query gets hard ...
-- use postgres aggregates ??
-- review multiuser operation for correctness
-- fix caching in the face of lost contact to the backend. If the
backend can't contact its server, then we should just save up caches,
and then when contact with backend re-established, we should spit
them out. But right now, this is broken. In particular,
the use of xaccGrouparkSaved screws up some status bits ...
-- review & match up against docs at -- review & match up against docs at
http://www.lupercalia.net/gnc-db/ http://www.lupercalia.net/gnc-db/
-- use version numbers for commodities. Right now, multi-user
updates of commodities are not detected (this seem OK for
now, since this is a rare occurrance, right ???)

View File

@ -260,9 +260,12 @@ pgendAccountGetCheckpoint (PGBackend *be, Checkpoint *chk)
PQclear (result); PQclear (result);
return; return;
} }
chk->balance = atoll(DB_GET_VAL("balance", j)); if (0 < nrows )
chk->cleared_balance = atoll(DB_GET_VAL("cleared_balance", j)); {
chk->reconciled_balance = atoll(DB_GET_VAL("reconciled_balance", j)); chk->balance = atoll(DB_GET_VAL("balance", j));
chk->cleared_balance = atoll(DB_GET_VAL("cleared_balance", j));
chk->reconciled_balance = atoll(DB_GET_VAL("reconciled_balance", j));
}
} }
PQclear (result); PQclear (result);

View File

@ -2,7 +2,7 @@
SQL Tables SQL Tables
---------- ----------
These mostly parallel the data structures in the gnc engine. These mostly parallel the data structures in the gnc engine.
See gnc-init.txt for more info. See table-create.sql for more info.
Session Table, Session Modes Session Table, Session Modes
@ -20,10 +20,10 @@ functioning.
to debug, and has reasonable demands on the database for small to debug, and has reasonable demands on the database for small
datasets. datasets.
This mode is guarenteed to clobber any sort of changes made by This mode is guaranteed to clobber any sort of changes made by
other users (in the same way that multiple file writers clobber other users (in the same way that multiple file writers clobber
each other). Thus, this mode is mutually exclusive of any other, each other). Thus, this mode is mutually exclusive of any other,
and te engine prevents more than one concurrent user. and the engine prevents more than one concurrent user.
-- "Single User Update Mode" -- -- "Single User Update Mode" --
@ -34,18 +34,18 @@ functioning.
of a crash. of a crash.
-- "Multi-User Polled" -- -- "Multi-User Polled" --
Multiple users are assumed, Gnucash polls the database to detect Multiple users are assumed, GnuCash polls the database to detect
changes in the data. Partially Implemented. changes in the data. Partially Implemented.
-- "Multi-User Events" -- -- "Multi-User Events" --
Gnucash uses the SQL LISTEN/NOTIFY async message delivery routines. GnuCash uses the SQL LISTEN/NOTIFY async message delivery routines.
Not implemented. Not implemented.
Safety Lockout Safety Lockout
-------------- --------------
There is a safety lockout that prevents a single-user mode database from There is a safety lockout that prevents a single-user mode database from
being ccessed by another user, and from having a multi-user mode being accessed by another user, and from having a multi-user mode
database from being accessed by a single-user-mode client. database from being accessed by a single-user-mode client.
@ -62,7 +62,7 @@ If you want incremental deletion, then use the 'Single Update' mode.
m4 macros m4 macros
--------- ---------
Some of the code is auto-gen'ed from m4 macros. This mopstly just Some of the code is auto-gen'ed from m4 macros. This mostly just
simplifies some rather repetitive, cut-n-paste code that's identical simplifies some rather repetitive, cut-n-paste code that's identical
from function to function. If you can think of a better way ... from function to function. If you can think of a better way ...
@ -75,14 +75,14 @@ sql corruption.
KVP frames KVP frames
---------- ----------
Storage of KVP values in the sql database is treated more or less as Storage of KVP values in the sql database is treated more or less as
described in the main kvp docs. The hierarchical structure is converted described in the main KVP docs. The hierarchical structure is converted
into 'paths' by concatenating key names, and using / as the separator. into 'paths' by concatenating key names, and using / as the separator.
(Thus, paths look like file-paths). The root of each frame is (Thus, paths look like file-paths). The root of each frame is
associated with a guid (and thus, a url kvp://12341234/some/kvp/keys, associated with a guid (and thus, a url kvp://12341234/some/kvp/keys,
where 12341234 is the guid). where 12341234 is the guid).
The implementation caches the paths, associating a 32-bit inode number The implementation caches the paths, associating a 32-bit inode number
with each path. Caching is done because the same path names will recurr with each path. Caching is done because the same path names will recur
frequently for different guids (e.g. /reconcile-info/last-date will frequently for different guids (e.g. /reconcile-info/last-date will
occur in most accounts). occur in most accounts).
@ -95,3 +95,17 @@ the type. Note that the binary type and the glist type are not currently
implemented. The glist type could be implemented, as long as the glist implemented. The glist type could be implemented, as long as the glist
only stored strings ... The binary type could be implemented with blobs. only stored strings ... The binary type could be implemented with blobs.
Version Numbers
---------------
Both the Account structure, and the Transaction structure, have version
numbers in them. These are used to compare the sql and the engine
contents, and update the one or the other as appropriate. Version
numbers would not be necessary for single-user access, but are important
for multi-user access, where several engines must be kept in sync with
the database contents. An alternative to version numbers might have
been the date of the last update. However, version numbers are better
than dates in the case where the engines reside on machines whose clocks
are not closely synchronized. (e.g. which may happen if the machines
are not using NTP for time synchronization; or, e.g. if one machine failed
to have daylight-savings time set correctly: its transactions would be
an hour newer/older than the others, leading to bad updates).

View File

@ -231,13 +231,15 @@ gpointer pgendGetResults (PGBackend *be,
} }
/* Compare the date of last modification. /* Compare the date of last modification.
* This is a special date comp to make the m4 macros simpler. * This is a special date comp to
* (1) make the m4 macros simpler, and
* (2) avoid needless updates
*/ */
#define COMP_NOW(sqlname,fun,ndiffs) { \ #define COMP_NOW(sqlname,fun,ndiffs) { \
Timespec eng_time = xaccTransRetDateEnteredTS(ptr); \ Timespec eng_time = xaccTransRetDateEnteredTS(ptr); \
Timespec sql_time = gnc_iso8601_to_timespec_local( \ Timespec sql_time = gnc_iso8601_to_timespec_local( \
DB_GET_VAL(sqlname,0)); \ DB_GET_VAL(sqlname,0)); \
if (eng_time.tv_sec != sql_time.tv_sec) { \ if (eng_time.tv_sec > sql_time.tv_sec) { \
char buff[80]; \ char buff[80]; \
gnc_timespec_to_iso8601_buff(eng_time, buff); \ gnc_timespec_to_iso8601_buff(eng_time, buff); \
PINFO("mis-match: %s sql='%s' eng=%s", sqlname, \ PINFO("mis-match: %s sql='%s' eng=%s", sqlname, \

View File

@ -47,7 +47,8 @@ CREATE TABLE gncAccount (
description TEXT, description TEXT,
notes TEXT, notes TEXT,
type TEXT NOT NULL, type TEXT NOT NULL,
commodity TEXT NOT NULL CHECK (commodity <>'') commodity TEXT NOT NULL CHECK (commodity <>''),
version INT4 NOT NULL
); );
-- CREATE INDEX gncAccount_pg_idx ON gncAccount (parentGuid); -- CREATE INDEX gncAccount_pg_idx ON gncAccount (parentGuid);
@ -56,12 +57,13 @@ CREATE TABLE gncAccount (
-- hack alert -- add kvp frames ?? -- hack alert -- add kvp frames ??
CREATE TABLE gncTransaction ( CREATE TABLE gncTransaction (
transGuid CHAR(32) PRIMARY KEY, transGuid CHAR(32) PRIMARY KEY,
date_entered DATETIME DEFAULT 'NOW', date_entered DATETIME DEFAULT 'NOW',
date_posted DATETIME, date_posted DATETIME,
num TEXT, num TEXT,
description TEXT, description TEXT,
currency TEXT NOT NULL CHECK (currency <> '') currency TEXT NOT NULL CHECK (currency <> ''),
version INT4 NOT NULL
); );
CREATE INDEX gncTransaction_posted_idx ON gncTransaction (date_posted); CREATE INDEX gncTransaction_posted_idx ON gncTransaction (date_posted);

View File

@ -12,6 +12,7 @@ define(`account', `gncAccount, Account, Account,
notes, , char *, xaccAccountGetNotes(ptr), notes, , char *, xaccAccountGetNotes(ptr),
type, , char *, xaccAccountTypeEnumAsString(xaccAccountGetType(ptr)), type, , char *, xaccAccountTypeEnumAsString(xaccAccountGetType(ptr)),
commodity, , char *, gnc_commodity_get_unique_name(xaccAccountGetCommodity(ptr)), commodity, , char *, gnc_commodity_get_unique_name(xaccAccountGetCommodity(ptr)),
version, , int32, xaccAccountGetVersion(ptr),
parentGUID, , GUID *, xaccAccountGetGUID(xaccAccountGetParentAccount(ptr)), parentGUID, , GUID *, xaccAccountGetGUID(xaccAccountGetParentAccount(ptr)),
accountGUID, KEY, GUID *, xaccAccountGetGUID(ptr), accountGUID, KEY, GUID *, xaccAccountGetGUID(ptr),
') ')
@ -44,6 +45,7 @@ define(`transaction', `gncTransaction, Transaction, Transaction,
currency, , commod, gnc_commodity_get_unique_name(xaccTransGetCurrency(ptr)), currency, , commod, gnc_commodity_get_unique_name(xaccTransGetCurrency(ptr)),
date_entered, , now, "NOW", date_entered, , now, "NOW",
date_posted, , Timespec, xaccTransRetDatePostedTS(ptr), date_posted, , Timespec, xaccTransRetDatePostedTS(ptr),
version, , int32, xaccTransGetVersion(ptr),
transGUID, KEY, GUID *, xaccTransGetGUID(ptr), transGUID, KEY, GUID *, xaccTransGetGUID(ptr),
') ')