@Test public void testHandleRequestPartitionClosedSlave() throws Exception { final int partition = 1; final int opaque = 0; final int maxSize = 1024; final long offset = 10; this.metaConfig.setTopics(Arrays.asList(this.topic)); this.metaConfig.closePartitions(this.topic, partition, partition); final MessageStore store = this.mocksControl.createMock(MessageStore.class); EasyMock.expect(this.storeManager.getMessageStore(this.topic, partition)).andReturn(store); final MessageSet set = this.mocksControl.createMock(MessageSet.class); EasyMock.expect(store.slice(offset, maxSize)).andReturn(set); final GetCommand request = new GetCommand( this.topic, this.metaConfig.getSlaveGroup(), partition, offset, maxSize, opaque); // this.conn.response(new BooleanCommand(request.getOpaque(), // HttpStatus.Forbidden, "partition[" // + this.metaConfig.getBrokerId() + "-" + request.getPartition() + // "] have been closed")); set.write(request, this.sessionContext); EasyMock.expectLastCall(); this.mocksControl.replay(); this.getProcessor.handleRequest(request, this.conn); this.mocksControl.verify(); assertEquals(0, this.statsManager.getCmdGetMiss()); assertEquals(1, this.statsManager.getCmdGets()); assertEquals(0, this.statsManager.getCmdOffsets()); }
@Test public void testHandleRequestNormal() throws Exception { final int partition = 1; final int opaque = 0; final int maxSize = 1024; final long offset = 10; final MessageStore store = this.mocksControl.createMock(MessageStore.class); EasyMock.expect(this.storeManager.getMessageStore(this.topic, partition)).andReturn(store); final MessageSet set = this.mocksControl.createMock(MessageSet.class); EasyMock.expect(store.slice(offset, maxSize)).andReturn(set); final GetCommand request = new GetCommand(this.topic, this.group, partition, offset, maxSize, opaque); set.write(request, this.sessionContext); EasyMock.expectLastCall(); this.mocksControl.replay(); this.getProcessor.handleRequest(request, this.conn); this.mocksControl.verify(); assertEquals(0, this.statsManager.getCmdGetMiss()); assertEquals(1, this.statsManager.getCmdGets()); assertEquals(0, this.statsManager.getCmdOffsets()); }
@Test public void testHandleRequestArrayIndexOutOfBounds() throws Exception { final int partition = 1; final int opaque = 0; final int maxSize = 1024; final long offset = 10; final long newOffset = 512; final MessageStore store = this.mocksControl.createMock(MessageStore.class); EasyMock.expect(this.storeManager.getMessageStore(this.topic, partition)).andReturn(store); EasyMock.expect(store.slice(offset, maxSize)).andThrow(new ArrayIndexOutOfBoundsException()); EasyMock.expect(store.getNearestOffset(offset)).andReturn(newOffset); this.conn.response(new BooleanCommand(opaque, HttpStatus.Moved, String.valueOf(newOffset))); EasyMock.expectLastCall(); this.mocksControl.replay(); final GetCommand request = new GetCommand(this.topic, this.group, partition, offset, maxSize, opaque); this.getProcessor.handleRequest(request, this.conn); this.mocksControl.verify(); assertEquals(1, this.statsManager.getCmdGetMiss()); assertEquals(1, this.statsManager.getCmdGets()); assertEquals(1, this.statsManager.getCmdOffsets()); }
@Test public void testHandleRequestGreatThanMaxOffsetSliceNull() throws Exception { final int partition = 1; final int opaque = 0; final int maxSize = 1024; final long offset = 10; final MessageStore store = this.mocksControl.createMock(MessageStore.class); EasyMock.expect(this.storeManager.getMessageStore(this.topic, partition)).andReturn(store); EasyMock.expect(store.slice(offset, maxSize)).andReturn(null); this.conn.response( new BooleanCommand( opaque, HttpStatus.NotFound, "Could not find message at position " + offset)); EasyMock.expect(store.getMaxOffset()).andReturn(offset - 1); EasyMock.expectLastCall(); this.mocksControl.replay(); final GetCommand request = new GetCommand(this.topic, this.group, partition, offset, maxSize, opaque); this.getProcessor.handleRequest(request, this.conn); this.mocksControl.verify(); assertEquals(1, this.statsManager.getCmdGetMiss()); assertEquals(1, this.statsManager.getCmdGets()); assertEquals(0, this.statsManager.getCmdOffsets()); }
@Test public void testHandleRequestMaxOffset() throws Exception { // 从实际最大的offset开始订阅 final int partition = 1; final int opaque = 0; final int maxSize = 1024; final long offset = Long.MAX_VALUE; final long realMaxOffset = 100; final MessageStore store = this.mocksControl.createMock(MessageStore.class); EasyMock.expect(this.storeManager.getMessageStore(this.topic, partition)).andReturn(store); EasyMock.expect(store.slice(offset, maxSize)).andReturn(null); this.conn.response(new BooleanCommand(opaque, HttpStatus.Moved, String.valueOf(realMaxOffset))); EasyMock.expect(store.getMaxOffset()).andReturn(realMaxOffset); EasyMock.expectLastCall(); this.mocksControl.replay(); final GetCommand request = new GetCommand(this.topic, this.group, partition, offset, maxSize, opaque); this.getProcessor.handleRequest(request, this.conn); this.mocksControl.verify(); assertEquals(1, this.statsManager.getCmdGetMiss()); assertEquals(1, this.statsManager.getCmdGets()); assertEquals(1, this.statsManager.getCmdOffsets()); }
@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); } } } } }); } }