Repository: libsql/libsql
File: libsql-server/src/connection/libsql.rs (Rust)

Code before:
        mut builder: B,
    ) -> Result<B> {
        use rusqlite::TransactionState as Tx;

        let (state, txn_timeout) = {
            let lock = this.lock();
            let txn_timeout = lock.config_store.get().txn_timeout.unwrap_or(TXN_TIMEOUT);
            (lock.state.clone(), txn_timeout)
        };

        let mut results = Vec::with_capacity(pgm.steps.len());
        builder.init(&this.lock().builder_config)?;
        let mut previous_state = this
            .lock()
            .conn
            .transaction_state(Some(DatabaseName::Main))?;

        let mut has_timeout = false;
        for step in pgm.steps() {
            let mut lock = this.lock();

            if !has_timeout {
                if let Some(slot) = &lock.slot {
                    let mut is_stolen = slot.is_stolen.lock();
                    if *is_stolen || Instant::now() > slot.expires_at() {
                        // we mark ourselves as stolen to notify any waiting lock thief.
                        if !*is_stolen {
                            lock.rollback();
                        }
                        *is_stolen = true;
                        has_timeout = true;
                    }
                }
            }

            // once there was a timeout, invalidate all the program steps
            if has_timeout {
                lock.slot = None;
                builder.begin_step()?;
                builder.step_error(Error::LibSqlTxTimeout)?;
                builder.finish_step(0, None)?;
                continue;
            }

            let res = lock.execute_step(step, &results, &mut builder)?;

            let new_state = lock.conn.transaction_state(Some(DatabaseName::Main))?;
            match (previous_state, new_state) {
                // lock was upgraded, claim the slot
                (Tx::None | Tx::Read, Tx::Write) => {
                    let slot = Arc::new(TxnSlot {

Review comment (suggestion):
Shouldn't this be in opposite order?
```
let stolen = *is_stolen
*is_stolen = true;
if !stolen {
  lock.rollback();
}
```

Code after:
            .lock()
            .config_store
            .get()
            .txn_timeout
            .unwrap_or(TXN_TIMEOUT);

        let mut results = Vec::with_capacity(pgm.steps.len());
        builder.init(&this.lock().builder_config)?;
        let mut previous_state = this
            .lock()
            .conn
            .transaction_state(Some(DatabaseName::Main))?;

        let mut has_timeout = false;
        for step in pgm.steps() {
            let mut lock = this.lock();

            if !has_timeout {
                if let Some(slot) = &lock.slot {
                    let mut is_stolen = slot.is_stolen.lock();
                    if *is_stolen || Instant::now() > slot.expires_at() {
                        // we mark ourselves as stolen to notify any waiting lock thief.
                        if !*is_stolen {
                            lock.rollback();
                        }
                        *is_stolen = true;
                        has_timeout = true;
                    }
                }
            }

            // once there was a timeout, invalidate all the program steps
            if has_timeout {
                lock.slot = None;
                builder.begin_step()?;
                builder.step_error(Error::LibSqlTxTimeout)?;
                builder.finish_step(0, None)?;
                continue;
            }

            let ret = lock.execute_step(step, &results, &mut builder);
            // /!\ always make sure that the state is updated before returning
            previous_state = lock.update_state(this.clone(), previous_state, txn_timeout)?;
            let res = ret?;

            results.push(res);
        }

        {
            let mut lock = this.lock();
            let is_autocommit = lock.conn.is_autocommit();