Hi there,
We have a function that reads a collection of documents in the database, and
then inserts N new documents into the collection depending on the results of
the first read. We need this behaviour to be atomic, and so we explicitly take
locks using xdmp:lock-for-update. This effectively forces the entire read and
then conditional insert into a single threaded operation (which is fine).
The problem is this, our function looks like this -
declare private function load-entities(
$entities as element()*,
$etag-map as map:map,
$entity-id as xs:string?,
$is-orphaned-series-item-allowed as xs:boolean,
$missing-etag-allowed as xs:boolean,
$ignore-duplicate-updates as xs:boolean
) as element(store:etag-map) {
let $_ := xdmp:set-transaction-mode("update")
return
let $entity-ids := fn:distinct-values($entities/c:id)
let $_ := $entity-ids ! xdmp:lock-for-update(.)
return
let $etag-map := _load-entities($entities, $etag-map,
$entity-id, $is-orphaned-series-item-allowed, $missing-etag-allowed,
$ignore-duplicate-updates)
return
let $_ := xdmp:commit()
return
$etag-map
};
This all appears to work fine... however reading the documentation
http://docs.marklogic.com/6.0/xdmp:rollback it seems that we should explicitly
rollback the transaction if we encounter an error. Our function is itself
called from a REST function library which expects to capture errors (using
catch) and then modify the http response code etc appropriately depending on
the error. If we use xdmp:rollback in a try/catch within our function pasted
above, this causes our REST API to break as there is no way to `bubble` the
error up, because it appears that xdmp:rollback terminates the processing of
the query immediately. For example we have tried this -
declare private function load-entities(
$entities as element()*,
$etag-map as map:map,
$entity-id as xs:string?,
$is-orphaned-series-item-allowed as xs:boolean,
$missing-etag-allowed as xs:boolean,
$ignore-duplicate-updates as xs:boolean
) as element(store:etag-map) {
let $_ := xdmp:set-transaction-mode("update")
return
try {
let $entity-ids := fn:distinct-values($entities/c:id)
let $_ := $entity-ids ! xdmp:lock-for-update(.)
return
let $etag-map := _load-entities($entities, $etag-map,
$entity-id, $is-orphaned-series-item-allowed, $missing-etag-allowed,
$ignore-duplicate-updates)
return
let $_ := xdmp:commit()
return
$etag-map
} catch($e) {
(xdmp:rollback(),
xdmp:rethrow()
)
}
};
The problem being if we call xdmp:rollback before xdmp:rethow, it appears that
rethow is never called so our REST API fails to see the error and just returns
HTTP 200. Likewise if we call xdmp:rethrow before xdmp:rollback, it seems that
xdmp:rollback is never called. I guess I kinda expected that behaviour... but
how do we actually solve our problem then?
How *bad* would it be to not actually call xdmp:rollback in terms of
transactions being collected when they timeout?
Please keep in mind that this is a large code-base and whilst it has some
design issues, refactoring everything at present is not really an option.
Cheers Adam.
DISCLAIMER
This message is intended only for the use of the person(s) ("Intended
Recipient") to whom it is addressed. It may contain information, which is
privileged and confidential. Accordingly any dissemination, distribution,
copying or other use of this message or any of its content by any person other
than the Intended Recipient may constitute a breach of civil or criminal law
and is strictly prohibited. If you are not the Intended Recipient, please
contact the sender as soon as possible.
Reed Business Information Limited. Registered Office: Quadrant House, The
Quadrant, Sutton, Surrey, SM2 5AS, UK.
Registered in England under Company No. 151537
_______________________________________________
General mailing list
[email protected]
http://developer.marklogic.com/mailman/listinfo/general