final void acknowledge(
      ConnectionContext context,
      final TopicMessageStore destination,
      final String clientId,
      final String subscriptionName,
      final MessageId messageId,
      final MessageAck ack)
      throws IOException {

    if (ack.isInTransaction()) {
      if (ack.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.acknowledge(context, clientId, subscriptionName, messageId, ack);
      } else {
        Tx tx = getTx(ack.getTransactionId());
        tx.add(
            new RemoveMessageCommand(context) {
              public MessageAck getMessageAck() {
                return ack;
              }

              public Future<Object> run(ConnectionContext ctx) throws IOException {
                destination.acknowledge(ctx, clientId, subscriptionName, messageId, ack);
                return AbstractMessageStore.FUTURE;
              }
            });
      }
    } else {
      destination.acknowledge(context, clientId, subscriptionName, messageId, ack);
    }
  }
  Future<Object> asyncAddTopicMessage(
      ConnectionContext context, final MessageStore destination, final Message message)
      throws IOException {

    if (message.getTransactionId() != null) {
      if (message.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.addMessage(context, message);
        return AbstractMessageStore.FUTURE;
      } else {
        Tx tx = getTx(message.getTransactionId());
        tx.add(
            new AddMessageCommand(context) {
              @Override
              public Message getMessage() {
                return message;
              }

              @Override
              public Future<Object> run(ConnectionContext ctx) throws IOException {
                return destination.asyncAddTopicMessage(ctx, message);
              }
            });
        return AbstractMessageStore.FUTURE;
      }
    } else {
      return destination.asyncAddTopicMessage(context, message);
    }
  }
  final void removeAsyncMessage(
      ConnectionContext context, final MessageStore destination, final MessageAck ack)
      throws IOException {

    if (ack.isInTransaction()) {
      if (ack.getTransactionId().isXATransaction()
          || theStore.isConcurrentStoreAndDispatchTransactions() == false) {
        destination.removeAsyncMessage(context, ack);
      } else {
        Tx tx = getTx(ack.getTransactionId());
        tx.add(
            new RemoveMessageCommand(context) {
              @Override
              public MessageAck getMessageAck() {
                return ack;
              }

              @Override
              public Future<Object> run(ConnectionContext ctx) throws IOException {
                destination.removeMessage(ctx, ack);
                return AbstractMessageStore.FUTURE;
              }
            });
      }
    } else {
      destination.removeAsyncMessage(context, ack);
    }
  }
 /** 添加消息,为了保证添加顺序,这里不得不加锁 */
 @Override
 public void addMessage(
     final MessageStore store, final long msgId, final PutCommand putCmd, JournalLocation location)
     throws IOException {
   if (location == null) {
     // 非重放,添加put日志
     final AppendMessageCommand appendCmd =
         AppendMessageCommand.newBuilder()
             .setMessageId(msgId)
             .setPutCommand(ByteString.copyFrom(putCmd.encode().array()))
             .build();
     final TxCommand txCommand =
         TxCommand.newBuilder()
             .setCmdType(TxCommandType.APPEND_MSG)
             .setCmdContent(appendCmd.toByteString())
             .build();
     final Tx tx = this.getInflyTx(putCmd.getTransactionId());
     if (tx != null) {
       location = this.journalStore.write(txCommand, null, tx.location, false);
     } else {
       location = this.journalStore.write(txCommand, null, null, false);
     }
   }
   final Tx tx = this.getTx(putCmd.getTransactionId(), location);
   tx.add(store, msgId, putCmd);
 }
  @Override
  public synchronized void recover(final TransactionRecoveryListener listener) throws IOException {
    // 所有本地事务都回滚
    Map<Object, Tx> copyMap = null;
    synchronized (this.inflightTransactions) {
      copyMap = new HashMap<Object, JournalTransactionStore.Tx>(this.inflightTransactions);
      // this.inflightTransactions.clear();
    }
    for (final Map.Entry<Object, Tx> entry : copyMap.entrySet()) {
      this.rollback((TransactionId) entry.getKey());
      if (log.isDebugEnabled()) {
        log.debug("Rollback inflight transaction:" + entry.getKey());
      }
    }
    // 恢复XA中的prepared事务
    this.doingRecover = true;
    try {
      Map<TransactionId, Tx> txs = null;
      synchronized (this.preparedTransactions) {
        txs = new LinkedHashMap<TransactionId, Tx>(this.preparedTransactions);
      }

      for (final Map.Entry<TransactionId, Tx> entry : txs.entrySet()) {
        final Object txid = entry.getKey();
        final Tx tx = entry.getValue();
        listener.recover((XATransactionId) txid, tx.getRequests());
      }
    } finally {
      this.doingRecover = false;
    }
  }
  public void commit(
      TransactionId txid, boolean wasPrepared, Runnable preCommit, Runnable postCommit)
      throws IOException {
    if (txid != null) {
      if (!txid.isXATransaction() && theStore.isConcurrentStoreAndDispatchTransactions()) {
        if (preCommit != null) {
          preCommit.run();
        }
        Tx tx = inflightTransactions.remove(txid);
        if (tx != null) {
          List<Future<Object>> results = tx.commit();
          boolean doneSomething = false;
          for (Future<Object> result : results) {
            try {
              result.get();
            } catch (InterruptedException e) {
              theStore.brokerService.handleIOException(new IOException(e.getMessage()));
            } catch (ExecutionException e) {
              theStore.brokerService.handleIOException(new IOException(e.getMessage()));
            } catch (CancellationException e) {
            }
            if (!result.isCancelled()) {
              doneSomething = true;
            }
          }
          if (postCommit != null) {
            postCommit.run();
          }
          if (doneSomething) {
            KahaTransactionInfo info = getTransactionInfo(txid);
            theStore.store(new KahaCommitCommand().setTransactionInfo(info), true, null, null);
          }
        } else {
          // The Tx will be null for failed over clients - lets run their post commits
          if (postCommit != null) {
            postCommit.run();
          }
        }

      } else {
        KahaTransactionInfo info = getTransactionInfo(txid);
        theStore.store(
            new KahaCommitCommand().setTransactionInfo(info), true, preCommit, postCommit);
        forgetRecoveredAcks(txid);
      }
    } else {
      LOG.error("Null transaction passed on commit");
    }
  }
Example #7
0
 @Test
 public void testConstructor() {
   byte[] rawTx =
       Utils.hexStringToByteArray(
           "0100000001bdc0141fe3e5c2223a6d26a95acbf791042d93f9d9b8b38f133bf7adb5c1e293010000006a47304402202214770c0f5a9261190337273219a108132a4bc987c745db8dd6daded34b0dcb0220573de1d973166024b8342d6b6fef2a864a06cceee6aee13a910e5d8df465ed2a01210382b259804ad8d88b96a23222e24dd5a130d39588e78960c9e9b48a5b49943649ffffffff02a0860100000000001976a91479a7bf0bba8359561d4dab457042d7b632d5e64188ac605b0300000000001976a914b036c529faeca8040232cc4bd5918e709e90c4ff88ac00000000");
   Tx tx = new Tx(rawTx);
   byte[] txBytes = tx.bitcoinSerialize();
   assertTrue(Arrays.equals(rawTx, txBytes));
   byte[] exceptTxHash =
       Utils.reverseBytes(
           Utils.hexStringToByteArray(
               "584985ca8a9ed57987da36ea3d13fe05a7c498f2098ddeb6c8d0f3214067640c"));
   byte[] txHash = tx.getTxHash();
   for (Out out : tx.getOuts()) {
     String outAddress = out.getOutAddress();
   }
   assertTrue(Arrays.equals(exceptTxHash, txHash));
 }
Example #8
0
  @Test
  public void testDb() {
    Tx tx = new Tx();
    byte[] txHash =
        Utils.reverseBytes(
            Utils.hexStringToByteArray(
                "f8a8335594d4c883f367e003cb3832015640f24714b48bd21cf6fbe84a617dfe"));
    tx.setTxHash(
        Utils.reverseBytes(
            Utils.hexStringToByteArray(
                "f8a8335594d4c883f367e003cb3832015640f24714b48bd21cf6fbe84a617dfe")));
    tx.setBlockNo(304942);
    tx.setTxTime((int) new Date().getTime() / 1000);
    tx.setTxVer(1);
    In inPut = new In();
    inPut.setPrevTxHash(
        Utils.reverseBytes(
            Utils.hexStringToByteArray(
                "d7f4efff7aeaffc1630dd3653e923a233fd463f9dc7dd4f97bb5cbf0cf99e56a")));
    inPut.setInSn(0);
    inPut.setTxHash(txHash);
    inPut.setInSequence(1);
    inPut.setInSignature(txHash);

    tx.addInput(inPut);
    Out out = new Out();
    out.setTxHash(txHash);
    out.setOutSn(0);
    out.setOutValue(3400);
    out.setOutScript(
        Utils.hexStringToByteArray("76a914abceaddc7d791f749671c17dfa36e9b17a4b055588ac"));
    out.setOutStatus(Out.OutStatus.spent);
    out.setOutAddress("test");
    tx.addOutput(out);
    AbstractDb.txProvider.add(tx);
    Tx testTx = AbstractDb.txProvider.getTxDetailByTxHash(txHash);
    assertEquals(
        Utils.bytesToHexString(tx.getTxHash()), Utils.bytesToHexString(testTx.getTxHash()));
  }
Example #9
0
  public void intercept(final Invocation inv) {
    Config config = Tx.getConfigWithTxConfig(inv);
    if (config == null) config = DbKit.getConfig();

    if (actionKeySet.contains(inv.getActionKey())) {
      DbPro.use(config.getName())
          .tx(
              new IAtom() {
                public boolean run() throws SQLException {
                  inv.invoke();
                  return true;
                }
              });
    } else {
      inv.invoke();
    }
  }
  @Override
  public void commit(final TransactionId txid, final boolean wasPrepared) throws IOException {
    final Tx tx;
    if (wasPrepared) {
      synchronized (this.preparedTransactions) {
        tx = this.preparedTransactions.remove(txid);
      }
    } else {
      synchronized (this.inflightTransactions) {
        tx = this.inflightTransactions.remove(txid);
      }
    }
    if (tx == null) {
      return;
    }
    // Append messages
    final Map<MessageStore, List<Long>> msgIds = tx.getMsgIds();
    final Map<MessageStore, List<PutCommand>> putCommands = tx.getPutCommands();
    final Map<String, AddMsgLocation> locations =
        new LinkedHashMap<String, JournalTransactionStore.AddMsgLocation>();

    final int count = msgIds.size();

    for (final Map.Entry<MessageStore, List<Long>> entry : msgIds.entrySet()) {
      final MessageStore msgStore = entry.getKey();
      final List<Long> ids = entry.getValue();
      final List<PutCommand> cmds = putCommands.get(msgStore);
      // Append message
      msgStore.append(
          ids,
          cmds,
          new AppendCallback() {

            @Override
            public void appendComplete(final Location location) {
              // Calculate checksum
              final int checkSum =
                  CheckSum.crc32(MessageUtils.makeMessageBuffer(ids, cmds).array());
              final String description = msgStore.getDescription();
              // Store append location
              synchronized (locations) {
                locations.put(
                    description,
                    new AddMsgLocation(
                        location.getOffset(), location.getLength(), checkSum, description));
                // 处理完成
                if (locations.size() == count) {
                  // 将位置信息序列化,并作为tx
                  // command的附加数据存储,这部分数据的长度是固定的,因此可以在replay的时候更改
                  final ByteBuffer localtionBytes = AddMsgLocationUtils.encodeLocation(locations);

                  TxCommand msg = null;
                  // Log transaction
                  final int attachmentLen = localtionBytes.remaining();
                  if (txid.isXATransaction()) {
                    final TransactionOperation to =
                        TransactionOperation.newBuilder() //
                            .setType(TransactionType.XA_COMMIT) //
                            .setTransactionId(txid.getTransactionKey()) //
                            .setWasPrepared(wasPrepared) //
                            .setDataLength(attachmentLen) // 设置附加数据长度
                            .build();
                    msg =
                        TxCommand.newBuilder()
                            .setCmdType(TxCommandType.TX_OP)
                            .setCmdContent(to.toByteString())
                            .build();
                  } else {
                    final TransactionOperation to =
                        TransactionOperation.newBuilder() //
                            .setType(TransactionType.LOCAL_COMMIT) //
                            .setTransactionId(txid.getTransactionKey()) //
                            .setWasPrepared(wasPrepared) //
                            .setDataLength(attachmentLen) // 设置附加数据长度
                            .build();
                    msg =
                        TxCommand.newBuilder()
                            .setCmdType(TxCommandType.TX_OP)
                            .setCmdContent(to.toByteString())
                            .build();
                  }
                  // 记录commit日志,并附加位置信息
                  try {
                    JournalTransactionStore.this.journalStore.write(
                        msg, localtionBytes, tx.location, true);
                  } catch (final IOException e) {
                    throw new RuntimeException("Write tx log failed", e);
                  }
                }
              }
            }
          });
    }
  }