Received: from localhost (unknown [200.46.208.211]) by mail.postgresql.org (Postfix) with ESMTP id 7987A634726 for ; Mon, 1 Jun 2009 06:55:48 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by localhost (mx1.hub.org [200.46.208.211]) (amavisd-maia, port 10024) with ESMTP id 62922-07 for ; Mon, 1 Jun 2009 06:55:40 -0300 (ADT) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-bw0-f163.google.com (mail-bw0-f163.google.com [209.85.218.163]) by mail.postgresql.org (Postfix) with ESMTP id 24E556345E8 for ; Mon, 1 Jun 2009 06:55:45 -0300 (ADT) Received: by bwz7 with SMTP id 7so7713848bwz.19 for ; Mon, 01 Jun 2009 02:55:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:cc:content-type :content-transfer-encoding; bh=5WUJFErP5OUQLt1fp5RIuBrAD1/OORJFlx3vjE017sc=; b=i55JgZvp1lFgsHuiMx3hQTXLBgO4w5NitMzhlhiz47dqM8CTe7CXlP/d5K4OewuN7a tPciNG3GVI8ZSMgVvCgZUFnDtfiluggs6vbO0wBVYbsmiF/npSrQtlDHGBdvCYMb1cbK NnvaSA9GPF9scIAuDgdzc9Smm+iv0p8Y+Xir0= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; b=Uob/unKfQr8NwnL3LhzRJ6Xil0XskeQVT0H3SwBHqc2l8XuLJ1yFt+FZwpWF+WVu6b PNpcQNFhb+eJ0zbVzqSA2PCvTjaZwgaz7YYcjQq3b8flAw0lHpr0EE24T83fKlpRVw6u 9I38kkKMIzHqExXU1yUhJ5TeS0Hd1jUJlDXoQ= MIME-Version: 1.0 Received: by 10.239.132.83 with SMTP id 19mr441758hbq.56.1243850144223; Mon, 01 Jun 2009 02:55:44 -0700 (PDT) In-Reply-To: References: Date: Mon, 1 Jun 2009 03:55:44 -0600 Message-ID: Subject: Re: Assigning data-entry tasks to multiple concurrent clients From: Scott Marlowe To: Jamie Tufnell Cc: pgsql-sql@postgresql.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0.014 tagged_above=0 required=5 tests=AWL=0.014 X-Spam-Level: X-Archive-Number: 200906/5 X-Sequence-Number: 32610 On Sun, May 31, 2009 at 9:54 PM, Jamie Tufnell wrot= e: > BEGIN; > SELECT * FROM records > WHERE in_edit_queue AND id NOT IN ( > =A0 SELECT record_id FROM locked_records > =A0 WHERE locked_since < now() + interval '5 minutes') > LIMIT 1; > > INSERT INTO locked_records (record_id, locked_since) VALUES (?, now()); > COMMIT; There's a race condition here but a unique constraint on record_id will take care of that, as long as you catch the error and retry. > Then to save (first-in wins is acceptable for this environment): > > BEGIN; > UPDATE records SET in_edit_queue =3D false WHERE id =3D ? AND in_edit_que= ue =3D > true; > DELETE FROM locked_records WHERE record_id =3D ?; > COMMIT; > > Is this a sane approach?=A0 Is there a better way to do this with Postgre= SQL? It'll work. The key to any kind of system like this is monitoring the progress for things that get stuck / fail to be processed and running them a second time if need be. I had a system to process 1M rows at a time from an 880M row db, and I used a secondary sequence and recid/1M to partition it out. So, the next job up grabs a sequence id from t secondary sequence, which matches the record(or set) to be processed. With that method there's no locking or anything needed, and no one needs to "check out" the records, because incrementing the secindary sequence is in fact checking them out. Just check the finished table to see if there's any holes and if there are put those jobs back in the queue by simply updating their id to the next value for the porimary id sequence. Sequences can be an elegant way of assigning jobs to multiple threads without locking issues.