乐趣区

关于redis:聊聊claudb的transaction-command

本文次要钻研一下 claudb 的 transaction command

TransactionState

claudb-1.7.1/src/main/java/com/github/tonivade/claudb/TransactionState.java

public class TransactionState implements Iterable<Request> {private List<Request> requests = new LinkedList<>();

  public void enqueue(Request request) {requests.add(request);
  }

  public int size() {return requests.size();
  }

  @Override
  public Iterator<Request> iterator() {return requests.iterator();
  }
}
  • TransactionState 实现了 Iterable<Request> 接口,它定义了 requests 属性,提供了 enqueue 办法将 request 增加到 requests 中

MultiCommand

claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/transaction/MultiCommand.java

@Command("multi")
@TxIgnore
public class MultiCommand implements DBCommand {

  private static final String TRASACTION_KEY = "tx";

  @Override
  public RedisToken execute(Database db, Request request) {if (!isTxActive(request.getSession())) {createTransaction(request.getSession());
      return responseOk();} else {return error("ERR MULTI calls can not be nested");
    }
  }

  private void createTransaction(Session session) {session.putValue(TRASACTION_KEY, new TransactionState());
  }

  private boolean isTxActive(Session session) {return session.getValue(TRASACTION_KEY).isPresent();}
}
  • MultiCommand 实现了 DBCommand 接口,其 execute 办法先判断 isTxActive,非 active 的话才 createTransaction

ExecCommand

claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/transaction/ExecCommand.java

@Command("exec")
@TxIgnore
public class ExecCommand implements DBCommand {

  @Override
  public RedisToken execute(Database db, Request request) {Option<TransactionState> transaction = getTransactionIfExists(request.getSession());
    if (transaction.isPresent()) {DBServerContext server = getClauDB(request.getServerContext());
      List<RedisToken> responses = new ArrayList<>();
      for (Request queuedRequest : transaction.get()) {responses.add(executeCommand(server, queuedRequest));
      }
      return RedisToken.array(responses);
    } else {return RedisToken.error("ERR EXEC without MULTI");
    }
  }

  private RedisToken executeCommand(DBServerContext server, Request queuedRequest) {RespCommand command = server.getCommand(queuedRequest.getCommand());
    return command.execute(queuedRequest);
  }

  private Option<TransactionState> getTransactionIfExists(Session session) {return session.removeValue("tx");
  }
}
  • ExecCommand 实现了 DBCommand 接口,其 execute 办法先通过 getTransactionIfExists 获取 transaction,若 transaction 不存在则报错,存在的话则遍历 transaction 的 queuedRequest,挨个执行 executeCommand(server, queuedRequest)

DiscardCommand

claudb-1.7.1/src/main/java/com/github/tonivade/claudb/command/transaction/DiscardCommand.java

@Command("discard")
@TxIgnore
public class DiscardCommand implements DBCommand {

  private static final String TX_KEY = "tx";

  @Override
  public RedisToken execute(Database db, Request request) {removeTransactionIfExists(request.getSession());

    return RedisToken.responseOk();}

  private Option<TransactionState> removeTransactionIfExists(Session session) {return session.removeValue(TX_KEY);
  }
}
  • DiscardCommand 实现了 DBCommand 接口,其 execute 办法执行 removeTransactionIfExists(request.getSession())

小结

claudb transaction 相干的 command 有 MultiCommand、ExecCommand、DiscardCommand

doc

  • transaction
退出移动版