/** add session to the end of queue when a transaction starts (depending on isolation mode) */
  public void beginAction(Session session, Statement cs) {

    if (session.hasLocks(cs)) {
      return;
    }

    writeLock.lock();

    try {
      if (cs.getCompileTimestamp() < database.schemaManager.getSchemaChangeTimestamp()) {
        cs = session.statementManager.getStatement(session, cs);
        session.sessionContext.currentStatement = cs;

        if (cs == null) {
          return;
        }
      }

      boolean canProceed = setWaitedSessionsTPL(session, cs);

      if (canProceed) {
        if (session.tempSet.isEmpty()) {
          lockTablesTPL(session, cs);

          // we don't set other sessions that would now be waiting for this one too
        } else {
          setWaitingSessionTPL(session);
        }
      } else {
        session.abortTransaction = true;
      }
    } finally {
      writeLock.unlock();
    }
  }
  /** add session to the end of queue when a transaction starts (depending on isolation mode) */
  public void beginAction(Session session, Statement cs) {

    synchronized (liveTransactionTimestamps) {
      session.actionTimestamp = nextChangeTimestamp();

      if (!session.isTransaction) {
        session.transactionTimestamp = session.actionTimestamp;
        session.isTransaction = true;

        liveTransactionTimestamps.addLast(session.actionTimestamp);
      }
    }

    if (session.hasLocks()) {
      return;
    }

    try {
      writeLock.lock();

      boolean canProceed = beginActionTPL(session, cs);

      if (!canProceed) {
        session.abortTransaction = true;
      }
    } finally {
      writeLock.unlock();
    }
  }