[XQZone General] Guaranteed unique?
Andy Townsend
atownsen at wiley.co.uk
Thu Dec 8 01:54:22 PST 2005
Howard,
Can you not simply use xdmp:eval() rather than xdmp:eval-in() to do the
same thing in the same database.
Also depending on your scenario you could grab blocks of IDs in the way
that Joel suggested - so long as the number of IDs required is relatively
easy to determine. The advantage there would be you could be sure of
getting consecutive IDs, if that was important.
Here's a variation of the example code from Joel that does both:
define function next-id ($doc-uri,$num-ids as xs:integer) as xs:integer {
let $eval := fn:concat(
"let $doc-uri :='",$doc-uri,"'
let $num-ids :=",fn:string($num-ids),"
let $id := doc($doc-uri)/id
let $next-val :=
if ($id castable as xs:integer) then xs:integer($id) + 1
else 1
let $next-node := <id>{$next-val + $num-ids - 1}</id>
let $insert :=
if ($id) then xdmp:node-replace ($id, $next-node)
else xdmp:document-insert ($doc-uri, $next-node)
return $next-val")
return xdmp:eval($eval)
}
let $seq := (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
let $nextid := next-id("tempuri",fn:count($seq)) - 1
(: we subtracted 1 from nextid as index starts at 1 in XQuery :)
return
for $x at $index in $seq
return $index + $nextid
Andy
|-----------------------------+-------------------------------------------|
| "Howard Katz" | |
| <howardk at fatdog.com> | |
| Sent by: | To|
| general-bounces at xqzone.mar| "'Gen|
| klogic.com | eral |
| | XQZon|
| 08/12/2005 01:43 | e |
| | Discu|
| Please respond to | ssion|
| General XQZone | '" |
| Discussion | <gene|
| <general at xqzone.marklog| ral at x|
| ic.com> | qzone|
| | .mark|
| | logic|
| | .com>|
| | cc|
| | |
| | Subject|
| | RE: |
| | [XQZo|
| | ne |
| | Gener|
| | al] |
| | Guara|
| | nteed|
| | uniqu|
| | e? |
| | |
| | |
| | |
| | |
| | |
| | |
|-----------------------------+-------------------------------------------|
I'm trying to do something similar and am encountering the samed dreaded
XDMP-CONFLICTINGUPDATES message. I'm calling next-id( ) from within a "for"
loop. Is it that static analysis of the query is seeing multiple
xdmp:replace-nodes() -- tho they're actually invoked sequentially -- and
thus throws this error?
Unfortunately I don't have the luxury of doing an eval-in() in another
database. Are there any other workarounds within the same db? I can see
grabbing all the id's in the document, doing an appropriate "order by", and
assigning the largest value + 1 as the next value to be assigned, but that
doesn't seem like a lot of fun for a large document.
Howard
> -----Original Message-----
> From: general-bounces at xqzone.marklogic.com
> [mailto:general-bounces at xqzone.marklogic.com] On Behalf Of
> Stewart, Joel (LNG-DAY)
> Sent: November 28, 2005 8:02 AM
> To: General XQZone Discussion
> Subject: RE: [XQZone General] Guaranteed unique?
>
> I have been wondering how to accomplish this when needing to
> call it a
> number of times from within an xquery function, e.g.:
>
> define function next-id ($doc-uri) as xs:integer {
> let $id := doc($doc-uri)/id
> let $next-val :=
> if ($id castable as xs:integer) then xs:integer
> ($id) + 1
> else 1
> let $next-node := <id>{$next-val}</id>
> let $insert :=
> if ($id) then xdmp:node-replace ($id, $next-node)
> else xdmp:document-insert ($doc-uri, $next-node)
>
> return $next-val
> }
>
> let $seq := (1,2,3,4,5,6,7,8,9)
> return
> for $x in $seq
> return next-id("tempuri")
>
> running this will result in
> XDMP-CONFLICTINGUPDATES: Conflicting updates
> xdmp:document-insert("tempuri", /id, (), (), 0) and
> xdmp:document-insert("tempuri", /id, (), (), 0) at line 18
>
>
> If I was to call this from a Java layer that iterates the nodes to be
> inserted, I recognize this method would work such that you
> either get a
> number or you get an exception. Retry logic would need to
> be written.
>
> We put a lot of work in XQuery modules, and iterate large numbers of
> nodes and do many inserts within the xquery function for performance.
> To my knowledge, we have not needed an auto-increment function in all
> this, but I have often wondered what we should do should that need
> arise. Hopefully, the number of ids that will be needed can be
> determined easily and quickly before invoking the functions
> that do the
> inserts. In this way, we can pass in a sequence or range of
> ids. But
> if the count of nodes is hard or expensive to determine - I
> was trying
> to think of a work around.
>
> One idea is to use eval-in. I have been wondering if using
> that to put
> your ids in another database would work around the above issue.
> Apparently it does. By using eval-in, the "next-id" document is
> actually committed. So trying the following will work if you crate a
> new DB to actually execute the "next-id" function. The code could be
> more pretty by putting next-id in a module in that db, but
> it gets the
> idea across.
>
> define function next-id ($doc-uri) {
> let $func :=
> fn:concat("
> let $doc-uri :=""",$doc-uri,"""
> let $id := doc($doc-uri)/id
> let $next-val :=
> if ($id castable as xs:integer) then xs:integer
> ($id) + 1
> else 1
> let $next-node := <id>{$next-val}</id>
> let $insert :=
> if ($id) then xdmp:node-replace ($id, $next-node)
> else xdmp:document-insert ($doc-uri, $next-node)
>
> return $next-val
> ")
>
> return xdmp:eval-in($func, xdmp:database("ANOTHER-DB"))
>
> }
>
> let $seq := (1,2,3,4,5,6,7,8,9)
> return
> for $x in $seq
> return next-id("tempuri")
>
> So, running this will work. The hard part will be putting error
> handling and retry logic in the function calling it - if it
> so happens
> two threads get on that node at the same time and cause conflicting
> updates. But I think this goes a long way toward what is
> needed to be
> implemented natively in marklogic - some "autoincrement"
> function that
> is not bound to the same rollback, and is atomic such that
> you will not
> get the conflicting updates exception.
>
> Other ideas are welcomed.
>
> Thanks.
> joel
>
> -----Original Message-----
> From: general-bounces at xqzone.marklogic.com
> [mailto:general-bounces at xqzone.marklogic.com] On Behalf Of
> Ron Hitchens
> Sent: Tuesday, November 22, 2005 7:40 PM
> To: General XQZone Discussion
> Subject: Re: [XQZone General] Guaranteed unique?
>
>
> Here is a function to do what Ian describes, lifted
> from the xfaqtor code available on xqzone:
>
>
> (: Return a monotonically increasing integer (xs:integer) value.
> Store the value in the root node of doc ($doc-uri).
> You could enhance this file to store IDs for multiple uses.
> Logic is to fetch the current id, add one if it exists
> or assign the
> value to one if it doesn't yet exist, then replace or
> insert the new
> value before returning it.
> :)
> define function next-id ($doc-uri) as xs:integer
> {
> let $id := doc($doc-uri)/id
> let $next-val :=
> if ($id castable as xs:integer) then xs:integer
> ($id) + 1
> else 1
> let $next-node := <id>{$next-val}</id>
> let $insert :=
> if ($id) then xdmp:node-replace ($id, $next-node)
> else xdmp:document-insert ($doc-uri, $next-node)
>
> return $next-val
> }
>
>
> On Nov 22, 2005, at 4:15 PM, Ian Small wrote:
>
> > Andy -
> >
> > Just create a document that contains the serial number in
> > question. Write some simple XQuery to retrieve the id from the
> > document, increment it, and update the document (using xdmp:node-
> > replace(), etc.).
> >
> > Because your XQuery module is performing an "update", it
> will block
> > all other requests trying to update that same document, thereby
> > guaranteeing unique IDs.
> >
> > Only "queries" (ie. requests which are statically analyzed to be
> > "read-only" requests) run lock-free per your description.
> Updates
> > (ie. requests which are statically analyzed to potentially change
> > the state of the database) lock documents and consequently block
> > each other as appropriate.
> >
> > ian
> >
> > -----Original Message-----
> > From: general-bounces at xqzone.marklogic.com [mailto:general-
> > bounces at xqzone.marklogic.com] On Behalf Of Andy Townsend
> > Sent: Tuesday, November 22, 2005 1:43 PM
> > To: general at xqzone.marklogic.com
> > Subject: [XQZone General] Guaranteed unique?
> >
> >
> >
> >
> > Anyone know a nice way to generate guaranteed unique
> sequential IDs
> > with XQuery in Mark Logic?
> >
> > So I can for example create the values for: id="1" ,
> id="2", etc...
> > and be sure that two users cannot ever pick up the same number.
> > Just having a document in the database with the current number
> > doesn't seem enough to me because I believe there would be a race
> > condition where two users could start at about the same
> time and so
> > see the same initial 'state' of the database which I presume the
> > XQuery would insist they both saw throughout their queries.
> >
> > I thought that document-locks might get me there (though in
> > probably contravention of the standard) but have not had any joy
> > with those as yet
> >
> > In Java it would be easy - just a serialised block - equally easy
> > in C++, but what about XQuery?
> >
> > Someone must have done this already! :-)
> >
> > Thanks
> >
> > Andy
> >
> >
> #############################################################
> #########
> > The information contained in this e-mail and any subsequent
> > correspondence is private and confidential and intended
> solely for
> > the named recipient(s). If you are not a named recipient,
> you must
> > not copy, distribute, or disseminate the information, open any
> > attachment, or take any action in reliance on it. If you have
> > received the e-mail in error, please notify the sender and delete
> > the e-mail.
> >
> > Any views or opinions expressed in this e-mail are those of the
> > individual sender, unless otherwise stated. Although this e-mail
> > has been scanned for viruses you should rely on your own virus
> > check, as the sender accepts no liability for any damage arising
> > out of any bug or virus infection.
> >
> #############################################################
> #########
> > _______________________________________________
> > General mailing list
> > General at xqzone.marklogic.com
> > http://xqzone.com/mailman/listinfo/general
> > _______________________________________________
> > General mailing list
> > General at xqzone.marklogic.com
> > http://xqzone.com/mailman/listinfo/general
>
> ---
> Ron Hitchens {ron.hitchens at marklogic.com} 650-655-2351
>
>
> _______________________________________________
> General mailing list
> General at xqzone.marklogic.com
> http://xqzone.com/mailman/listinfo/general
> _______________________________________________
> General mailing list
> General at xqzone.marklogic.com
> http://xqzone.com/mailman/listinfo/general
>
_______________________________________________
General mailing list
General at xqzone.marklogic.com
http://xqzone.com/mailman/listinfo/general
######################################################################
The information contained in this e-mail and any subsequent
correspondence is private and confidential and intended solely
for the named recipient(s). If you are not a named recipient,
you must not copy, distribute, or disseminate the information,
open any attachment, or take any action in reliance on it. If you
have received the e-mail in error, please notify the sender and delete
the e-mail.
Any views or opinions expressed in this e-mail are those of the
individual sender, unless otherwise stated. Although this e-mail has
been scanned for viruses you should rely on your own virus check, as
the sender accepts no liability for any damage arising out of any bug
or virus infection.
######################################################################
More information about the General
mailing list