Yeah, that's what I had coded previously. Sorry for all the back-and-forth guys, I was trying to be lazy and reduce round-trips. I'll switch back to this code. I appreciate the feedback!
On 3/1/12 3:27 PM, "Marshall McMullen" <[email protected]> wrote: >Yes, the results are guaranteed to be the same order of the requests. > >However, the first one that fails will cause the entire multi to be >aborted. So, if say the first one fails, then you won't know if the others >after that would have failed. > >I'd suggest doing something entire different, such as (pseudo-code): > >List<Ops> ops >for(path in paths) > if (!Exists(path)) { > ops.add(Op.Create(path)); > } > >Does that make sense? I'm suggesting you use the non-multi code to check >if >it exists or not. If not, you can append any ops related to that path into >your ops list. > > >On Thu, Mar 1, 2012 at 11:14 PM, Shelley, Ryan ><[email protected]>wrote: > >> Right, I did this: >> >> (psuedo-code) >> List<Ops> ops >> For(path in paths) >> ops.add( Op.check(path, -1) ) >> EndFor >> >> List<OpResult> Results = Zk.multi(ops) >> >> This causes an exception to be thrown on the first path that doesn't >> exist. It doesn't return back a list with one OpResult flagged with an >> error. I was under the impression I'd get back a bunch of OpResult >>objects >> with flags of error, or otherwise, and then I could build another list >>of >> operations to create what's needed (which, even if it did work, the >> CheckResult object doesn't include the path, so I'm just hoping the >> results are in the same order as the operations were listed in, as I >>have >> to infer the path I'll need to build from the position of the OpResult >>in >> the list). >> >> >> >> On 3/1/12 3:05 PM, "Ted Dunning" <[email protected]> wrote: >> >> >No. I meant one call full of checks and a second call with any >>necessary >> >creates. >> > >> >Sent from my iPhone >> > >> >On Mar 1, 2012, at 11:17 AM, "Shelley, Ryan" <[email protected]> >> >wrote: >> > >> >> Ok, I tried this with the Op.create and found that it will throw a >> >> KeeperException on the first path that doesn't exist. It doesn't >>return >> >> back an OpResult with an "error" type. I can still use this, and just >> >> catch the exception and create the node in the exception, but I was >> >>under >> >> the impression that I could do this in two trips. One trip to get >>back a >> >> list of OpResults from the check that would inform me if the path >> >>existed >> >> or not, and a second trip to create all the paths that don't exist >>(and >> >>as >> >> a note, the CheckResult object doesn't include the path, so I have to >> >> infer it from the order of my original list of paths used to create >>the >> >> multi-check). >> >> >> >> -Ryan >> >> >> >> On 2/29/12 7:16 PM, "Ted Dunning" <[email protected]> wrote: >> >> >> >>> On Wed, Feb 29, 2012 at 7:04 PM, Marshall McMullen < >> >>> [email protected]> wrote: >> >>> >> >>>> Yes, Ted's right. The multi has to fail as that's part of the >>contract >> >>>> it >> >>>> guarantees. >> >>>> >> >>>> The only thing you could do, which will significantly narrow the >>race >> >>>> condition, is as you're *building *the multi, check if the path >> >>>>already >> >>>> exists. If so, then don't add the create op for that path into the >> >>>> multi. >> >>>> Of course this may not work in every situation, but we use that >> >>>> approach in >> >>>> many code paths and it works well. >> >>>> >> >>> >> >>> Another approach is to compose one multi with Op.exists() for each >> >>>level >> >>> so >> >>> that you find everything you need, then create another with the >>correct >> >>> Op.create() operations. That gets the problem down to two server >> >>> round-trips but still has the race condition. >> >> >> >>
