return LDAP_SUCCESS;
}
+static int txn_result( Operation *op, SlapReply *rs )
+{
+ return rs->sr_err;
+}
+
int txn_end_extop(
Operation *op, SlapReply *rs )
{
ber_len_t len;
ber_int_t commit=1;
struct berval txnid;
+ Operation *o, *p;
+ Connection *c = op->o_conn;
Statslog( LDAP_DEBUG_STATS, "%s TXN END\n",
op->o_log_prefix, 0, 0, 0, 0 );
return LDAP_PROTOCOL_ERROR;
}
- op->o_bd = op->o_conn->c_authz_backend;
+ op->o_bd = c->c_authz_backend;
if( backend_check_restrictions( op, rs,
(struct berval *)&slap_EXOP_TXN_END ) != LDAP_SUCCESS )
{
}
/* acquire connection lock */
- ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+ ldap_pvt_thread_mutex_lock( &c->c_mutex );
- if( op->o_conn->c_txn != CONN_TXN_SPECIFY ) {
+ if( c->c_txn != CONN_TXN_SPECIFY ) {
rs->sr_text = "invalid transaction identifier";
rc = LDAP_X_TXN_ID_INVALID;
goto done;
}
- op->o_conn->c_txn = CONN_TXN_SETTLE;
+ c->c_txn = CONN_TXN_SETTLE;
if( commit ) {
+ slap_callback cb = {0};
+ OpExtra *txn = NULL;
if ( op->o_abandon ) {
+ goto drain;
}
- if( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) ) {
+ if( LDAP_STAILQ_EMPTY(&c->c_txn_ops) ) {
/* no updates to commit */
rs->sr_text = "no updates to commit";
rc = LDAP_OPERATIONS_ERROR;
goto settled;
}
- rs->sr_text = "not yet implemented";
- rc = LDAP_UNWILLING_TO_PERFORM;
-
+ cb.sc_response = txn_result;
+ LDAP_STAILQ_FOREACH( o, &c->c_txn_ops, o_next ) {
+ o->o_bd = c->c_txn_backend;
+ p = o;
+ if ( !txn ) {
+ rc = o->o_bd->bd_info->bi_op_txn(o, SLAP_TXN_BEGIN, &txn );
+ if ( rc ) {
+ rs->sr_text = "couldn't start DB transaction";
+ rc = LDAP_OTHER;
+ goto drain;
+ }
+ } else {
+ LDAP_SLIST_INSERT_HEAD( &o->o_extra, txn, oe_next );
+ }
+ cb.sc_next = o->o_callback;
+ o->o_callback = &cb;
+ {
+ SlapReply rs = {REP_RESULT};
+ int opidx = slap_req2op( o->o_tag );
+ assert( opidx != SLAP_OP_LAST );
+ o->o_threadctx = op->o_threadctx;
+ o->o_tid = op->o_tid;
+ ldap_pvt_thread_mutex_unlock( &c->c_mutex );
+ rc = (&o->o_bd->bd_info->bi_op_bind)[opidx]( o, &rs );
+ ldap_pvt_thread_mutex_lock( &c->c_mutex );
+ }
+ if ( rc ) {
+ struct berval *bv = NULL;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+
+ ber_init_w_nullc( ber, LBER_USE_DER );
+ ber_printf( ber, "{i}", o->o_msgid );
+ ber_flatten( ber, &bv );
+ ber_free_buf( ber );
+ rs->sr_rspdata = bv;
+ o->o_bd->bd_info->bi_op_txn(o, SLAP_TXN_ABORT, &txn );
+ goto drain;
+ }
+ }
+ o = p;
+ rc = o->o_bd->bd_info->bi_op_txn(o, SLAP_TXN_COMMIT, &txn );
+ if ( rc ) {
+ rs->sr_text = "transaction commit failed";
+ rc = LDAP_OTHER;
+ }
} else {
rs->sr_text = "transaction aborted";
- rc = LDAP_SUCCESS;;
+ rc = LDAP_SUCCESS;
}
drain:
/* drain txn ops list */
+ while (( o = LDAP_STAILQ_FIRST( &c->c_txn_ops )) != NULL ) {
+ LDAP_STAILQ_REMOVE_HEAD( &c->c_txn_ops, o_next );
+ LDAP_STAILQ_NEXT( o, o_next ) = NULL;
+ slap_op_free( o, NULL );
+ }
settled:
- assert( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) );
- assert( op->o_conn->c_txn == CONN_TXN_SETTLE );
- op->o_conn->c_txn = CONN_TXN_INACTIVE;
- op->o_conn->c_txn_backend = NULL;
+ assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) );
+ assert( c->c_txn == CONN_TXN_SETTLE );
+ c->c_txn = CONN_TXN_INACTIVE;
+ c->c_txn_backend = NULL;
done:
/* release connection lock */
- ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &c->c_mutex );
return rc;
}
+int txn_preop( Operation *op, SlapReply *rs )
+{
+ int settle = 0;
+
+ /* acquire connection lock */
+ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+ if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
+ rs->sr_text = "invalid transaction identifier";
+ rs->sr_err = LDAP_X_TXN_ID_INVALID;
+ goto txnReturn;
+ } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
+ settle=1;
+ goto txnReturn;
+ }
+
+ if( op->o_conn->c_txn_backend == NULL ) {
+ op->o_conn->c_txn_backend = op->o_bd;
+
+ } else if( op->o_conn->c_txn_backend != op->o_bd ) {
+ rs->sr_text = "transaction cannot span multiple database contexts";
+ rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
+ goto txnReturn;
+ }
+
+ /* insert operation into transaction */
+ LDAP_STAILQ_REMOVE( &op->o_conn->c_ops, op, Operation, o_next );
+ LDAP_STAILQ_INSERT_TAIL( &op->o_conn->c_txn_ops, op, o_next );
+
+txnReturn:
+ /* release connection lock */
+ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+
+ if( !settle ) {
+ send_ldap_result( op, rs );
+ if ( !rs->sr_err )
+ rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
+ return rs->sr_err;
+ }
+ return LDAP_SUCCESS; /* proceed with operation */
+}
+
#endif /* LDAP_X_TXN */