Return-Path: Delivered-To: apmail-couchdb-user-archive@www.apache.org Received: (qmail 47664 invoked from network); 3 Feb 2010 18:14:09 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 3 Feb 2010 18:14:09 -0000 Received: (qmail 31531 invoked by uid 500); 3 Feb 2010 18:14:08 -0000 Delivered-To: apmail-couchdb-user-archive@couchdb.apache.org Received: (qmail 31463 invoked by uid 500); 3 Feb 2010 18:14:08 -0000 Mailing-List: contact user-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: user@couchdb.apache.org Delivered-To: mailing list user@couchdb.apache.org Received: (qmail 31453 invoked by uid 99); 3 Feb 2010 18:14:08 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 03 Feb 2010 18:14:08 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of andrew.melo@gmail.com designates 209.85.219.213 as permitted sender) Received: from [209.85.219.213] (HELO mail-ew0-f213.google.com) (209.85.219.213) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 03 Feb 2010 18:13:59 +0000 Received: by ewy5 with SMTP id 5so1712015ewy.32 for ; Wed, 03 Feb 2010 10:13:38 -0800 (PST) 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:content-type :content-transfer-encoding; bh=v1RWA0eziPbYQJbhIagD5f0g8SQqxsJCaKUT/2mUhfw=; b=tI4HVnUWnk2IwarRFLZyIFRQ8RLBOuvHQRH6Q9E/6ENmtzPeSkvLYAHCCxdFrkwqie FWpzHXLs+1V9xSJQLDJMoG1GrH445Af+hog36/Ym10hoO9xAkONkh1q0s5LV/j8pReyD iYr91Ml4EjNmthzHYDOugeavqMS+Yhv1iRG1U= 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 :content-type:content-transfer-encoding; b=K0WsjQ3l3fKGuc65NKBt70a+Kat/fexwLnFrXjTguJbPB7c/DDnaRcYZSDLjRxRvw9 5wmAct0SG9pDd9enQ/PADlUE3XxbW2+Zgk0k/LYAMN18TM/qQC8CtjIKbDSDvNYAFD8H U1J0NQxeFHeVpxNrFO8JBHJQH3/PSAXfidfGQ= MIME-Version: 1.0 Received: by 10.216.87.133 with SMTP id y5mr837577wee.139.1265220817861; Wed, 03 Feb 2010 10:13:37 -0800 (PST) In-Reply-To: <98a246a11002031007o998a242ta015fd3ac87df3c8@mail.gmail.com> References: <98a246a11002030729v51edbb91yd39f41f3e96c8f6e@mail.gmail.com> <20100203163741.GA9508@uk.tiscali.com> <98a246a11002031007o998a242ta015fd3ac87df3c8@mail.gmail.com> Date: Wed, 3 Feb 2010 12:13:37 -0600 Message-ID: Subject: Re: FIFO/LIFO accountancy From: Andrew Melo To: user@couchdb.apache.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On Wed, Feb 3, 2010 at 12:07 PM, Metin Akat wrote: > Hmm, one solution I hadn't thought about at all. > Thanks, Chris. I'll think about it. > So far the only difference is that I would probably choose the leading > event to be the document of purchase. > Then in a situation of race condition usually there won't be the need > to "raise an exception". Instead the =C2=A0 "FIFO process" will continue > with the next "batch". An exception will be risen only if we are out > of apples, and then we will issue a "cancellation of purchase" > document, or even better, will put the purchase order on queue (in a > case it makes sense) and order new apples from our supplier. > Yeah, I'm starting to like such an approach. Thanks again. What happens to the customer then? You've shown me a page saying "order complete" and then at some point down the line (whenever couchDB notices the probem or your state machine catches up on _changes), it realizes it can't fulfill the order. Even worse, all of the cheaper apples are actually gone, and all that's left are the more expensive ones. I think your better bet would be to use something that was aware of atomic commits handle the inventory-ing, and then export that data couch to run map/reduce over, rather than hoping to enforce atomic semantics on what is an unatomic subsystem. Best, Andrew > > > > On Wed, Feb 3, 2010 at 7:27 PM, Chris Anderson wrote: >> On Wed, Feb 3, 2010 at 8:37 AM, Brian Candler wrot= e: >>> On Wed, Feb 03, 2010 at 05:29:26PM +0200, Metin Akat wrote: >>>> So, we need some way to figure out which apples we sell first. (how >>>> much value to remove from the warehouse account). In order to do this >>>> we need to know how much have we sold till the moment. And this needs >>>> to be fault tolerant. >>>> For example, if somebody (at some other cash register in the store) >>>> sold 3 apples before our deal, our transactions would be quite a bit >>>> different. What if this happened one milisecond before we sell our >>>> apples? >>> >>> It sounds to me like this is a locking problem. You have an inventory o= f >>> (5 apples @ $2), (5 apples @ $3) and you want to remove from these pool= s >>> atomically, *without any chance of going negative* >>> >> >> You can do a state machine approach where you have 1 update "pull the >> apples off the shelf" and another one for the cash register. >> >> The register in this case would be an asynchronous background process. >> >> If you have a crash between pulling the apples of the shelf and the >> cash register, but the register is driven by _changes, it'll just pick >> right up after a crash. >> >> If you have a race condition and 2 users add the apples to their >> carts, whoever the cash register services first wins. The other user >> can get a "delayed shipping option" error message. >> >>> So your first thought might be to keep your stock of apples as a single >>> document, and use couchdb's 'optimistic locking' to prevent two concurr= ent >>> changes: >>> >>> { >>> =C2=A0"id":"apples", >>> =C2=A0"stock":{2.0=3D>5, 3.0=3D>5}, =C2=A0// cost price =3D> quantity >>> } >>> >>> That's fine (on a single couchdb node anyway). But then you want to rec= ord >>> the sale as another part of the same 'transaction', and post it to your >>> sales ledger and the customer's account receivable at the same time. = =C2=A0That >>> might work if the details of the sale were stored in the same document = as >>> the apples (a view can pull them out). e.g. >>> >>> { >>> =C2=A0"id":"apples", >>> =C2=A0"stock":{3.0=3D>4}, >>> =C2=A0"purchases":[ >>> =C2=A0 {"supplier":888, "orderno":123, "line":1, "qty":5, "cost":10.0}, >>> =C2=A0 {"supplier":888, "orderno":124, "line":1, "qty":5, "cost":15.0} >>> =C2=A0], >>> =C2=A0"sales":[ >>> =C2=A0{"cust":1234, "orderno":9999, "line":1, "qty":6, "price":30.0, "c= ost":13.0} >>> =C2=A0] >>> } >>> >>> But what if one customer decides to purchase apples and pears in the sa= me >>> order? =C2=A0In the event of a power loss, would it be acceptable for h= alf of the >>> order to be recorded? >>> >>> I think it might. If the order is a separate doc, and the order ID is p= osted >>> against each line item as shown above, you can identify orders which ha= ven't >>> been fully processed and hence complete the processing of them when the= app >>> restarts. >>> >>> This gives a very stock-centric view of your business processes. What i= f >>> your business takes apples out of the apples stock and manufactures it = into >>> cartons of apple juice, which it then sells? >>> >>> Maybe an RDBMS would be a better fit :-( >>> >>> B. >>> >> >> >> >> -- >> Chris Anderson >> http://jchrisa.net >> http://couch.io >> > --=20 -- Andrew Melo