Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1YLAVt-0002pr-AX for pgsql-sql@arkaria.postgresql.org; Tue, 10 Feb 2015 13:06:01 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.80) (envelope-from ) id 1YLAVs-0006An-Oz for pgsql-sql@arkaria.postgresql.org; Tue, 10 Feb 2015 13:06:00 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1YLAVq-00068K-Sl for pgsql-sql@postgresql.org; Tue, 10 Feb 2015 13:05:59 +0000 Received: from nm35-vm8.bullet.mail.ir2.yahoo.com ([212.82.97.131]) by magus.postgresql.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1YLAVm-00050e-Bk for pgsql-sql@postgresql.org; Tue, 10 Feb 2015 13:05:57 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.co.uk; s=s2048; t=1423573551; bh=72uSDbjJ+WzWMAumbypg6AFxX6r5+UbvvAD5a1ONwf4=; h=Date:From:Reply-To:To:In-Reply-To:References:Subject:From:Subject; b=DyUMosk424PwYpMOARmrr/t+NMPIUEMGZpvWRzNJU8AuNHQxCQfizS7YJlZxAZKLjlqvCu8y4VH/5roRnC+YQZ9pOcVIqg8hVPchXZXmWCW7IXquTwbndeO6P5QRNQ/5JjNJqGZcSzLDxG21f+faSyT9I2GNd/Hm0NRDCAB/m7b17NLK7stmPP1VbvcKxB315LHAn3MhCIppb9QKCS+UmN7h//RSTestH/JrzKyAzFRipWervjkoAqv5fyWpnYOSk2AoQeVw22bfPQGwINVr3SFqvR4ThLTifk2QSrR5fQQAz3D7UFkd/go5yJeSuKKc3gT3/wGfHh/C6WIWibCZPQ== Received: from [212.82.98.127] by nm35.bullet.mail.ir2.yahoo.com with NNFMP; 10 Feb 2015 13:05:51 -0000 Received: from [212.82.98.93] by tm20.bullet.mail.ir2.yahoo.com with NNFMP; 10 Feb 2015 13:05:51 -0000 Received: from [127.0.0.1] by omp1030.mail.ir2.yahoo.com with NNFMP; 10 Feb 2015 13:05:51 -0000 X-Yahoo-Newman-Property: ymail-3 X-Yahoo-Newman-Id: 817135.59243.bm@omp1030.mail.ir2.yahoo.com X-YMail-OSG: J.A_ipsVM1kJbM3RCiWAb94sLY47jXMvGDFUVJn8hBLTjyDD_iy0cIgp90n7K8Y bMKc5Zla0w3XFXvdn9.WIX3soTQqKbjDz0knVFfmh4pCv.9fHnIeDLSqxD3LDICAdxhLawrGChKO 8I1pxszleW5XwAvAd9rOy.6k28b32Em9tQMmDi_bSnH1C19obfXo_V7mIfx_j1P_aSWzuozL2ZFz 4Ku7Z3kfrV4t6ymOpbJc0CZP0Hd4tJhZelhzmUtdS1QrHOWx8J0GgktonwJxsQp6jS_xh6QolH8k 9vyHxgs9OpOkGrb34oNvGo.oky6SpjXW3HO8FLnBalooW9E3fWyWej.U9M9fHgY73uJfHkMA2QFr uehjH5Iouh7VycMfv4OtYQo2YUb7kAWCdcY0iGEeOwRUntjkw.NqgLPs0OJI5Yv1MxriD3w5wmu4 nok8qDT8AsfJVyyrKAqxoSDoUO3e8Gk18fTxCFuHN4ed_onQQoQXrdGev8f0pN7TR62mfBZgc64a N5V4LoHaKdRA_JM4R Received: by 217.12.8.245; Tue, 10 Feb 2015 13:05:51 +0000 Date: Tue, 10 Feb 2015 13:05:50 +0000 (UTC) From: Glyn Astill Reply-To: Glyn Astill To: Nii Gii , "pgsql-sql@postgresql.org" Message-ID: <521810732.2592114.1423573550866.JavaMail.yahoo@mail.yahoo.com> In-Reply-To: References: Subject: Re: Implementing incremental client updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Length: 3584 X-Pg-Spam-Score: -2.0 (--) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-sql Precedence: bulk Sender: pgsql-sql-owner@postgresql.org > From: Nii Gii >To: pgsql-sql@postgresql.org >Sent: Tuesday, 10 February 2015, 11:39 >Subject: [SQL] Implementing incremental client updates > > > >Dear all, > > >I am a newcomer to postgres and love it so far. I've given this problem a lot of thought already, RTFM to the best of my ability, but hit a dead end, so I need a nudge in the right direction. > > >I'm designing a database where each entity of interest has a "rowversion" column that gets assigned a value from a global sequence. So, in the simplest scenario, if I have two rows in table "emps": emp1 with rowversion@3 and emp2 with rowversion@5, then I know emp2 was modified after emp1. > > >This is to form the foundation of a data sync scenario, where a client knows they have everything up until @3 and now they need the latest updates (SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor). The problem here is, there's no way to interrogate the database for the "latest committed @rowversion that has none pending before it". An example scenario: > > >@3 - committed >@4 - committed >@5 - committed >@6 - in progress - not committed yet >@7 - in progress - not committed yet >@8 - committed >@9 - committed > > >When client asks for updated records, we ask the database for an appropriate new_anchor. Since the rows with rowversion @6 and @7 are still in progress, new_anchor has to be @5, so that our range query doesn't miss any uncommitted updates. Now the client can be confident it has everything up until @5. > > >So the actual problem distilled: how can this new_anchor be safely determined each time? > > >As you can probably tell I've borrowed this idea from SQL Server, where this problem is trivially solved by the min_active_rowversion() function. This function would return @6 in the above scenario, so your new_anchor is always going to be "min_active_rowversion()-1". I sort of had an idea how this could be implemented in postgres using an "active_rowversions" table, and a "SELECT min(id) FROM active_rowversions" but that would require READ UNCOMMITTED isolation, which is not available in postgres. > > >I would really appreciate any help or ideas. > I guess one way to tackle it would be to try and make the assignment of rowversions from the sequence transactional in some way. I'm not sure if that's possible without reinventing some sort of sequence behaviour with locking, but you might be able to achieve something workable by using a deferred trigger on the table to assign the sequence after the initial modification at transaction commit. There could be a race condition with this approach, but something like: CREATE OR REPLACE FUNCTION update_rowversion() RETURNS trigger AS $$ BEGIN UPDATE emps SET rowversion = nextval('rowversion_seq') WHERE = NEW.; RETURN NEW; END; $$ LANGUAGE plpgsql VOLATILE; CREATE CONSTRAINT TRIGGER emps_insert_rowversion AFTER INSERT ON emps DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE update_rowversion(); CREATE CONSTRAINT TRIGGER emps_update_rowversion AFTER UPDATE ON emps DEFERRABLE INITIALLY DEFERRED FOR EACH ROW WHEN (OLD.rowversion IS NOT DISTINCT FROM NEW.rowversion) EXECUTE PROCEDURE update_rowversion(); Obviously the downsides are that you're now doing extra work; an extra update, and the overhead of maintaining the deferred-trigger action queue. Another way to keep track of what is committed is to track the current snapshot, but there are complications there such as freezing of rows and xids wrapping around every 4 billion transcations. -- Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-sql