Пример #1
0
svn_error_t *
svn_sqlite__finish_savepoint(svn_sqlite__db_t *db,
                             svn_error_t *err)
{
  svn_sqlite__stmt_t *stmt;

  if (err)
    {
      svn_error_t *err2;

      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);

      if (!err2)
        {
          err2 = svn_error_trace(svn_sqlite__step_done(stmt));

          if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
            {
              /* Ok, we have a major problem. Some statement is still open,
                 which makes it impossible to release this savepoint.

                 ### See huge comment in rollback_transaction() for
                     further details */

              err2 = svn_error_trace(reset_all_statements(db, err2));
              err2 = svn_error_compose_create(
                          svn_error_trace(svn_sqlite__step_done(stmt)),
                          err2);
            }
        }

      err = svn_error_compose_create(err, err2);
      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_RELEASE_SAVEPOINT_SVN);

      if (!err2)
        err2 = svn_error_trace(svn_sqlite__step_done(stmt));

      return svn_error_compose_create(err, err2);
    }

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_RELEASE_SAVEPOINT_SVN));

  /* ### Releasing a savepoint can fail and leave the db connection
         unusable; see svn_sqlite__finish_transaction(). */
  return svn_error_trace(svn_sqlite__step_done(stmt));
}
Пример #2
0
/* The body of svn_sqlite__with_transaction() and
   svn_sqlite__with_immediate_transaction(), which see. */
static svn_error_t *
with_transaction(svn_sqlite__db_t *db,
                 svn_sqlite__transaction_callback_t cb_func,
                 void *cb_baton,
                 apr_pool_t *scratch_pool /* NULL allowed */)
{
  svn_error_t *err;

  err = cb_func(cb_baton, db, scratch_pool);

  /* Commit or rollback the sqlite transaction. */
  if (err)
    {
      svn_error_t *err2 = exec_sql(db, "ROLLBACK TRANSACTION;");

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* ### Houston, we have a problem!

             We are trying to rollback but we can't because some
             statements are still busy. This leaves the database
             unusable for future transactions as the current transaction
             is still open.

             As we are returning the actual error as the most relevant
             error in the chain, our caller might assume that it can
             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
             in fact the SQLite database is unusable until the statements
             started within this transaction are reset and the transaction
             aborted.

             We try to compensate by resetting all prepared but unreset
             statements; but we leave the busy error in the chain anyway to
             help diagnosing the original error and help in finding where
             a reset statement is missing. */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(
                      exec_sql(db, "ROLLBACK TRANSACTION;"),
                      err2);
        }

      return svn_error_compose_create(err,
                                      err2);
    }

  return svn_error_trace(exec_sql(db, "COMMIT TRANSACTION;"));
}
Пример #3
0
static svn_error_t *
rollback_transaction(svn_sqlite__db_t *db,
                     svn_error_t *error_to_wrap)
{
  svn_sqlite__stmt_t *stmt;
  svn_error_t *err;

  err = get_internal_statement(&stmt, db, STMT_INTERNAL_ROLLBACK_TRANSACTION);
  if (!err)
    {
      err = svn_error_trace(svn_sqlite__step_done(stmt));

      if (err && err->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* ### Houston, we have a problem!

             We are trying to rollback but we can't because some
             statements are still busy. This leaves the database
             unusable for future transactions as the current transaction
             is still open.

             As we are returning the actual error as the most relevant
             error in the chain, our caller might assume that it can
             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
             in fact the SQLite database is unusable until the statements
             started within this transaction are reset and the transaction
             aborted.

             We try to compensate by resetting all prepared but unreset
             statements; but we leave the busy error in the chain anyway to
             help diagnosing the original error and help in finding where
             a reset statement is missing. */
          err = svn_error_trace(reset_all_statements(db, err));
          err = svn_error_compose_create(
                      svn_error_trace(svn_sqlite__step_done(stmt)),
                      err);
        }
    }

  if (err)
    {
      /* Rollback failed, use a specific error code. */
      err = svn_error_create(SVN_SQLITE__ERR_ROLLBACK_FAILED, err,
                             _("SQLite transaction rollback failed"));
    }

  return svn_error_compose_create(error_to_wrap, err);
}
Пример #4
0
svn_error_t *
svn_sqlite__with_lock(svn_sqlite__db_t *db,
                      svn_sqlite__transaction_callback_t cb_func,
                      void *cb_baton,
                      apr_pool_t *scratch_pool)
{
  svn_error_t *err;
  int savepoint = db->savepoint_nr++;
  /* This buffer is plenty big to hold the SAVEPOINT and RELEASE commands. */
  char buf[32];

  snprintf(buf, sizeof(buf), "SAVEPOINT s%u", savepoint);
  SVN_ERR(exec_sql(db, buf));
  err = cb_func(cb_baton, db, scratch_pool);

  if (err)
    {
      svn_error_t *err2;

      snprintf(buf, sizeof(buf), "ROLLBACK TO s%u", savepoint);
      err2 = exec_sql(db, buf);

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* Ok, we have a major problem. Some statement is still open, which
             makes it impossible to release this savepoint.

             ### See huge comment in svn_sqlite__with_transaction for
                 further details */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(exec_sql(db, buf), err2);
        }

      snprintf(buf, sizeof(buf), "RELEASE   s%u", savepoint);
      err2 = svn_error_compose_create(exec_sql(db, buf), err2);

      return svn_error_trace(svn_error_compose_create(err, err2));
    }

  snprintf(buf, sizeof(buf), "RELEASE   s%u", savepoint);
  return svn_error_trace(exec_sql(db, buf));
}