26 #ifndef _BLOCKPUBLISHSTORE_H_
27 #define _BLOCKPUBLISHSTORE_H_
35 #include <amps/ampscrc.hpp>
36 #if __cplusplus >= 201103L || _MSC_VER >= 1900
42 #include <sys/timeb.h>
64 typedef Lock<BlockStore> BufferLock;
65 typedef Unlock<BlockStore> BufferUnlock;
69 SOW_DELETE_DATA = 0x01,
70 SOW_DELETE_FILTER = 0x02,
71 SOW_DELETE_KEYS = 0x04,
72 SOW_DELETE_BOOKMARK = 0x08,
73 SOW_DELETE_BOOKMARK_CANCEL = 0x10,
74 SOW_DELETE_UNKNOWN = 0x80
81 DEFAULT_BLOCK_HEADER_SIZE = 32,
82 DEFAULT_BLOCK_CHAIN_HEADER_SIZE = 64,
83 DEFAULT_BLOCKS_PER_REALLOC = 1000,
84 DEFAULT_BLOCK_SIZE = 2048
124 amps_uint32_t _blocksToWrite;
125 amps_uint32_t _totalRemaining;
127 amps_uint64_t _crcVal;
128 amps_uint64_t _nextInChain;
131 struct BlockChainHeader
133 amps_uint32_t _operation;
134 amps_uint32_t _commandIdLen;
135 amps_uint32_t _correlationIdLen;
136 amps_uint32_t _expirationLen;
137 amps_uint32_t _sowKeyLen;
138 amps_uint32_t _topicLen;
140 amps_uint32_t _ackTypes;
141 amps_uint32_t _unused[8];
143 : _operation(0), _commandIdLen(0), _correlationIdLen(0)
144 , _expirationLen(0), _sowKeyLen(0), _topicLen(0), _flag(-1)
155 return DEFAULT_BLOCK_HEADER_SIZE;
165 return DEFAULT_BLOCK_CHAIN_HEADER_SIZE;
201 amps_uint32_t blocksPerRealloc_ = 1000,
202 bool isFile_ =
false,
203 bool errorOnPublishGap_ =
false,
204 amps_uint32_t blockSize_ = DEFAULT_BLOCK_SIZE)
206 , _blockStore(buffer_, normalizeBlocksPerRealloc(blocksPerRealloc_, blockSize_),
207 DEFAULT_BLOCK_HEADER_SIZE,
208 normalizeBlockSize(blocksPerRealloc_, blockSize_))
210 , _maxDiscarded((amps_uint64_t)0), _lastSequence((amps_uint64_t)1)
218 BufferLock bufferGuard(_blockStore);
220 _metadataBlock = _blockStore.
get(1);
226 _metadataBlock->_sequence = (amps_uint64_t)0;
233 pBuffer->
putUint64((amps_uint64_t)VersionInfo::parseVersion(AMPS_CLIENT_VERSION));
253 return store(message_,
true);
268 const char* commandId, *correlationId, *expiration, *sowKey,
271 BlockHeader blockHeader;
272 BlockChainHeader chainHeader;
274 chainHeader._commandIdLen = (amps_uint32_t)dataLen;
276 chainHeader._correlationIdLen = (amps_uint32_t)dataLen;
278 chainHeader._expirationLen = (amps_uint32_t)dataLen;
280 chainHeader._sowKeyLen = (amps_uint32_t)dataLen;
282 chainHeader._topicLen = (amps_uint32_t)dataLen;
283 message_.getRawData(&data, &dataLen);
284 chainHeader._flag = -1;
286 chainHeader._operation = (amps_uint32_t)operation;
287 if (operation == Message::Command::SOWDelete)
291 chainHeader._flag = SOW_DELETE_DATA;
298 chainHeader._flag = SOW_DELETE_FILTER;
305 chainHeader._flag = SOW_DELETE_KEYS;
310 chainHeader._flag = SOW_DELETE_BOOKMARK;
313 size_t remaining = options.
len();
314 const void* next = NULL;
315 const void* start = (
const void*)(options.
data());
317 while (remaining >= 6 &&
318 (next = memchr(start, (
int)
'c', remaining)) != NULL)
320 remaining = (size_t)next - (
size_t)start;
321 if (remaining >= 6 && strncmp((
const char*)start,
324 chainHeader._flag = SOW_DELETE_BOOKMARK_CANCEL;
332 blockHeader._totalRemaining = (
333 (chainHeader._operation == Message::Command::Unknown)
336 + chainHeader._commandIdLen
337 + chainHeader._correlationIdLen
338 + chainHeader._expirationLen
339 + chainHeader._sowKeyLen
340 + chainHeader._topicLen
341 + (amps_uint32_t)dataLen));
342 size_t lastBlockLength = ((operation == Message::Command::Unknown) ? 0 :
344 blockHeader._blocksToWrite = ((operation == Message::Command::Unknown)
346 : ((amps_uint32_t)(blockHeader._totalRemaining
348 + ((lastBlockLength > 0) ? 1 : 0)));
349 blockHeader._crcVal = (amps_uint64_t)0ULL;
350 blockHeader._crcVal = _crc(commandId,
351 chainHeader._commandIdLen,
352 blockHeader._crcVal);
353 blockHeader._crcVal = _crc(correlationId,
354 chainHeader._correlationIdLen,
355 blockHeader._crcVal);
356 blockHeader._crcVal = _crc(expiration,
357 chainHeader._expirationLen,
358 blockHeader._crcVal);
359 blockHeader._crcVal = _crc(sowKey,
360 chainHeader._sowKeyLen,
361 blockHeader._crcVal);
362 blockHeader._crcVal = _crc(topic,
363 chainHeader._topicLen,
364 blockHeader._crcVal);
365 blockHeader._crcVal = _crc(data, dataLen, blockHeader._crcVal);
368 BufferLock bufferGuard(_blockStore);
369 Block* first = _blockStore.
get(blockHeader._blocksToWrite);
372 if (_lastSequence <= 2)
376 blockHeader._seq = ++_lastSequence;
381 message_.getMessage(),
385 _maxDiscarded = blockHeader._seq - 1;
387 if (blockHeader._seq >= _lastSequence)
389 _lastSequence = blockHeader._seq;
395 size_t topicWritten = 0UL;
396 size_t dataWritten = 0UL;
397 size_t commandWritten = 0UL;
398 size_t correlationWritten = 0UL;
399 size_t expirationWritten = 0UL;
400 size_t sowKeyWritten = 0UL;
402 for (
Block* next = first; next; next = next->_nextInChain)
404 next->_sequence = blockHeader._seq;
405 if (next->_nextInChain)
407 blockHeader._nextInChain = next->_nextInChain->_offset;
411 blockHeader._nextInChain = (amps_uint64_t)0;
415 pBuffer->
putBytes((
const char*)&blockHeader,
sizeof(BlockHeader));
417 blockHeader._crcVal = (amps_uint64_t)0;
423 pBuffer->
putBytes((
const char*)&chainHeader,
424 sizeof(BlockChainHeader));
433 if (commandWritten < chainHeader._commandIdLen)
435 size_t commandWrite = (chainHeader._commandIdLen - commandWritten < bytesRemaining) ? chainHeader._commandIdLen - commandWritten : bytesRemaining;
436 pBuffer->
putBytes(commandId + commandWritten,
438 bytesRemaining -= commandWrite;
439 commandWritten += commandWrite;
441 if (correlationWritten < chainHeader._correlationIdLen)
443 size_t correlationWrite = (chainHeader._correlationIdLen - correlationWritten < bytesRemaining) ? chainHeader._correlationIdLen - correlationWritten : bytesRemaining;
444 pBuffer->
putBytes(correlationId + correlationWritten,
446 bytesRemaining -= correlationWrite;
447 correlationWritten += correlationWrite;
449 if (bytesRemaining > 0 && expirationWritten < chainHeader._expirationLen)
451 size_t expWrite = (chainHeader._expirationLen - expirationWritten < bytesRemaining) ? chainHeader._expirationLen - expirationWritten : bytesRemaining;
452 pBuffer->
putBytes(expiration + expirationWritten, expWrite);
453 bytesRemaining -= expWrite;
454 expirationWritten += expWrite;
456 if (bytesRemaining > 0 && sowKeyWritten < chainHeader._sowKeyLen)
458 size_t sowKeyWrite = (chainHeader._sowKeyLen - sowKeyWritten < bytesRemaining) ? chainHeader._sowKeyLen - sowKeyWritten : bytesRemaining;
459 pBuffer->
putBytes(sowKey + sowKeyWritten, sowKeyWrite);
460 bytesRemaining -= sowKeyWrite;
461 sowKeyWritten += sowKeyWrite;
463 if (bytesRemaining > 0 && topicWritten < chainHeader._topicLen)
465 size_t topicWrite = (chainHeader._topicLen - topicWritten
467 ? chainHeader._topicLen - topicWritten
469 pBuffer->
putBytes(topic + topicWritten, topicWrite);
470 bytesRemaining -= topicWrite;
471 topicWritten += topicWrite;
473 if (bytesRemaining > 0 && dataWritten < dataLen)
475 size_t dataWrite = (dataLen - dataWritten < bytesRemaining) ?
476 dataLen - dataWritten : bytesRemaining;
477 pBuffer->
putBytes(data + dataWritten, dataWrite);
478 bytesRemaining -= dataWrite;
479 dataWritten += dataWrite;
485 _blockStore.
put(first);
488 AMPS_FETCH_ADD(&_stored, 1);
489 return blockHeader._seq;
501 BufferLock bufferGuard(_blockStore);
505 amps_uint64_t lastPersisted = _metadataBlock->_sequence;
507 if (index_ == (amps_uint64_t)0 || !_blockStore.
front() || index_ <= _maxDiscarded)
511 if (lastPersisted < index_)
515 _metadataBlock->_sequence = index_;
516 if (_maxDiscarded < index_)
518 _maxDiscarded = index_;
520 if (_lastSequence <= index_)
522 _lastSequence = index_;
529 else if (getErrorOnPublishGap() && index_ < lastPersisted)
531 std::ostringstream os;
532 os <<
"Server last saw " << index_ <<
" from Client but Store "
533 <<
"has already discarded up to " << lastPersisted
534 <<
" which would leave a gap of unreceived messages.";
535 throw PublishStoreGapException(os.str());
541 _maxDiscarded = index_;
542 AMPS_FETCH_SUB(&_stored, _blockStore.
put(index_));
544 if (lastPersisted >= index_)
550 _metadataBlock->_sequence = index_;
551 if (_lastSequence < index_)
553 _lastSequence = index_;
564 BufferLock bufferGuard(_blockStore);
566 if (!_blockStore.
front())
573 for (
Block* block = _blockStore.
front(); block; block = next)
576 replayOnto(block, replayer_);
577 next = block->_nextInList;
580 catch (
const StoreException&)
595 BufferLock bufferGuard(_blockStore);
597 if (!_blockStore.
front())
602 amps_uint64_t lastIdx = _blockStore.
back()->_sequence;
604 amps_uint64_t leastIdx = _blockStore.
front()->_sequence;
605 if (index_ >= leastIdx && index_ <= lastIdx)
608 while (block && block->_sequence != index_)
610 block = block->_nextInList;
619 sizeof(amps_uint32_t));
624 replayOnto(block, replayer_);
644 size_t count = (size_t)_stored;
658 BufferLock bufferGuard(_blockStore);
659 amps_uint64_t waitFor = _getHighestUnpersisted();
667 bool timedOut =
false;
668 AMPS_START_TIMER(timeout_);
670 while (!timedOut && _stored != 0
671 && waitFor >= _getLowestUnpersisted())
673 if (!_blockStore.
wait(timeout_))
676 AMPS_RESET_TIMER(timedOut, timeout_);
680 if (timedOut && _stored != 0
681 && waitFor >= _getLowestUnpersisted())
683 throw TimedOutException(
"Timed out waiting to flush publish store.");
688 while (_stored != 0 && waitFor >= _getLowestUnpersisted())
691 _blockStore.
wait(1000);
693 BufferUnlock unlck(_blockStore);
694 amps_invoke_waiting_function();
701 BufferLock bufferGuard(_blockStore);
702 return _getLowestUnpersisted();
705 amps_uint64_t getHighestUnpersisted()
const
707 BufferLock bufferGuard(_blockStore);
708 return _getHighestUnpersisted();
713 BufferLock bufferGuard(_blockStore);
714 return _getLastPersisted();
718 static size_t normalizeBlockCountValue(
size_t blocksPerRealloc_)
720 if (blocksPerRealloc_ == 0)
722 return DEFAULT_BLOCKS_PER_REALLOC;
724 if (blocksPerRealloc_ > BlockStore::MAX_BLOCKS_PER_REALLOC)
726 return BlockStore::MAX_BLOCKS_PER_REALLOC;
728 return blocksPerRealloc_;
731 static amps_uint32_t normalizeBlockSizeValue(amps_uint32_t blockSize_)
735 return DEFAULT_BLOCK_SIZE;
737 if (blockSize_ < DEFAULT_BLOCK_CHAIN_HEADER_SIZE * 2)
739 return DEFAULT_BLOCK_CHAIN_HEADER_SIZE * 2;
741 return blockSize_ & ~127U;
744 static amps_uint32_t normalizeBlocksPerRealloc(
size_t blocksPerRealloc_,
745 amps_uint32_t blockSize_)
747 size_t blocks = normalizeBlockCountValue(blocksPerRealloc_);
748 amps_uint32_t blockSize = normalizeBlockSizeValue(blockSize_);
750 if (blocks > (std::numeric_limits<size_t>::max)() / blockSize)
752 return DEFAULT_BLOCKS_PER_REALLOC;
754 return (amps_uint32_t)blocks;
757 static amps_uint32_t normalizeBlockSize(
size_t blocksPerRealloc_,
758 amps_uint32_t blockSize_)
760 size_t blocks = normalizeBlockCountValue(blocksPerRealloc_);
761 amps_uint32_t blockSize = normalizeBlockSizeValue(blockSize_);
763 if (blocks > (std::numeric_limits<size_t>::max)() / blockSize)
765 return DEFAULT_BLOCK_SIZE;
770 static size_t getInitialBufferSize(
size_t blocksPerRealloc_,
771 amps_uint32_t blockSize_)
773 return (
size_t)normalizeBlocksPerRealloc(blocksPerRealloc_, blockSize_)
774 * normalizeBlockSize(blocksPerRealloc_, blockSize_);
777 static bool canResize(
size_t requestedSize_,
void* vpThis_)
780 return me->callResizeHandler(requestedSize_);
783 amps_uint64_t _getLowestUnpersisted()
const
787 if (!_blockStore.
front())
791 return _blockStore.
front()->_sequence;
794 amps_uint64_t _getHighestUnpersisted()
const
798 if (!_blockStore.
back())
802 return _blockStore.
back()->_sequence;
805 amps_uint64_t _getLastPersisted(
void)
808 amps_uint64_t lastPersisted = (amps_uint64_t)0;
809 Buffer* pBuffer = _blockStore.
getBuffer();
811 lastPersisted = pBuffer->getUint64();
814 if (_lastSequence < lastPersisted)
816 _lastSequence = lastPersisted;
818 return lastPersisted;
822 lastPersisted = _maxDiscarded;
829 lastPersisted = (t.time * 1000 + t.millitm) * (amps_uint64_t)1000000;
832 gettimeofday(&tv, NULL);
833 lastPersisted = (amps_uint64_t)((tv.tv_sec * 1000) + (tv.tv_usec / 1000))
834 * (amps_uint64_t)1000000;
837 if (_lastSequence > 2)
839 amps_uint64_t low = _getLowestUnpersisted();
840 amps_uint64_t high = _getHighestUnpersisted();
843 lastPersisted = low - 1;
847 _lastSequence = high;
849 if (_lastSequence < lastPersisted)
851 lastPersisted = _lastSequence - 1;
856 _lastSequence = lastPersisted;
858 pBuffer->setPosition(_metadataBlock->_offset
859 +
sizeof(amps_uint32_t)
860 +
sizeof(amps_uint32_t));
861 pBuffer->putUint64(lastPersisted);
862 _metadataBlock->_sequence = lastPersisted;
863 return lastPersisted;
868 BufferLock bufferGuard(_blockStore);
870 Buffer* pBuffer = _blockStore.
getBuffer();
871 size_t size = pBuffer->
getSize();
876 _metadataBlock = _blockStore.
get(1);
877 _metadataBlock->_sequence = (amps_uint64_t)0;
878 pBuffer->setPosition(_metadataBlock->_offset);
881 pBuffer->putUint32(blockSize);
883 pBuffer->putUint64((amps_uint64_t)0);
885 pBuffer->putUint64((amps_uint64_t)VersionInfo::parseVersion(AMPS_CLIENT_VERSION));
887 pBuffer->putUint64((amps_uint64_t)0);
890 size_t numBlocks = size / blockSize;
891 if (size % blockSize > 0)
896 size_t existingBlocks = size / blockSize;
897 numBlocks = existingBlocks;
899 if (numBlocks > (std::numeric_limits<size_t>::max)() / blockSize)
901 throw StoreException(
"Publish Store size overflow during recovery.");
903 size_t alignedSize = numBlocks * blockSize;
904 amps_uint32_t blockCount = 0;
906 delete[] _blockStore.
resizeBuffer(alignedSize, &blockCount);
909 size_t actualSize = pBuffer->getSize();
910 size_t actualBlocks = actualSize / blockSize;
911 if (alignedSize > actualSize || actualSize % blockSize
912 || actualBlocks < numBlocks
913 || actualBlocks - existingBlocks != (
size_t)blockCount)
915 throw StoreException(
"Publish Store could not resize correctly during recovery, possibly due to resizeHandler refusing the request.");
917 numBlocks = actualBlocks;
921 amps_uint64_t maxIdx = 0;
922 amps_uint64_t minIdx = 0;
924 BlockHeader blockHeader;
926 Block* blocks =
new Block[numBlocks];
927 blocks[numBlocks - 1]._nextInList = 0;
930 _metadataBlock = blocks;
931 _metadataBlock->_nextInList = 0;
932 pBuffer->setPosition(0);
933 pBuffer->copyBytes((
char*)&blockHeader,
sizeof(BlockHeader));
941 if (blockHeader._blocksToWrite == 1)
944 throw StoreException(
"Unrecognized format for Store. Can't recover.");
946 if (blockHeader._blocksToWrite == 0)
948 pBuffer->setPosition(0);
949 pBuffer->putUint32(blockSize);
953 blockSize = blockHeader._blocksToWrite;
956 if (blockHeader._totalRemaining == 0)
958 pBuffer->setPosition(
sizeof(amps_uint32_t));
965 _metadataBlock->_sequence = blockHeader._seq;
966 if (_metadataBlock->_sequence
967 && _metadataBlock->_sequence < (amps_uint64_t)1000000)
969 pBuffer->setPosition(_metadataBlock->_offset
970 +
sizeof(amps_uint32_t)
971 +
sizeof(amps_uint32_t));
972 pBuffer->putUint64((amps_uint64_t)0);
973 _metadataBlock->_sequence = 0;
978 _maxDiscarded = _metadataBlock->_sequence;
979 _lastSequence = _maxDiscarded;
983 location += blockSize;
984 amps_uint32_t freeCount = 0;
985 Block* firstFree = NULL;
986 Block* endOfFreeList = NULL;
988 typedef std::map<amps_uint64_t, Block*> RecoverMap;
989 RecoverMap recoveredBlocks;
990 while (location < size)
993 pBuffer->setPosition(location);
994 pBuffer->copyBytes((
char*)&blockHeader,
sizeof(BlockHeader));
995 if ((blockHeader._seq > 0 && blockHeader._totalRemaining < size) &&
996 (!blockHeader._crcVal || recoveredBlocks.count(blockHeader._seq)))
999 location += blockSize;
1002 Block* block = blocks[++blockNum].setOffset(location);
1003 bool recovered =
false;
1004 if (blockHeader._seq > 0 && blockHeader._totalRemaining < size)
1007 block->_sequence = blockHeader._seq;
1009 if (maxIdx < blockHeader._seq)
1011 maxIdx = blockHeader._seq;
1013 if (minIdx > blockHeader._seq)
1015 minIdx = blockHeader._seq;
1018 recoveredBlocks[blockHeader._seq] = block;
1020 while (blockHeader._nextInChain != (amps_uint64_t)0)
1022 Block* chain = blocks[++blockNum]
1023 .setOffset((
size_t)blockHeader._nextInChain);
1024 chain->_nextInList = 0;
1025 pBuffer->setPosition((
size_t)blockHeader._nextInChain
1026 +
sizeof(amps_uint32_t)
1027 +
sizeof(amps_uint32_t)
1028 +
sizeof(amps_uint64_t)
1029 +
sizeof(amps_uint64_t));
1030 blockHeader._nextInChain = pBuffer->getUint64();
1031 block->_nextInChain = chain;
1033 block->_sequence = blockHeader._seq;
1042 endOfFreeList->_nextInList = block;
1048 endOfFreeList = block;
1051 location += blockSize;
1055 endOfFreeList->_nextInList = 0;
1058 if (maxIdx > _lastSequence)
1060 _lastSequence = maxIdx;
1062 if (minIdx > _maxDiscarded + 1)
1064 _maxDiscarded = minIdx - 1;
1066 if (_maxDiscarded > _metadataBlock->_sequence)
1068 _metadataBlock->_sequence = _maxDiscarded;
1069 pBuffer->setPosition(_metadataBlock->_offset + 8);
1070 pBuffer->putUint64(_maxDiscarded);
1073 AMPS_FETCH_ADD(&_stored, (
long)(recoveredBlocks.size()));
1074 for (RecoverMap::iterator i = recoveredBlocks.begin();
1075 i != recoveredBlocks.end(); ++i)
1079 end->_nextInList = i->second;
1089 end->_nextInList = 0;
1096 void replayOnto(Block* block_, StoreReplayer& replayer_)
1099 size_t start = block_->_offset;
1100 size_t position = start;
1101 Buffer* pBuffer = _blockStore.
getBuffer();
1103 BlockHeader blockHeader;
1104 pBuffer->copyBytes((
char*)&blockHeader,
sizeof(BlockHeader));
1105 if (blockHeader._totalRemaining == 0)
1111 BlockChainHeader blockChainHeader;
1112 pBuffer->copyBytes((
char*)&blockChainHeader,
sizeof(blockChainHeader));
1113 if (blockChainHeader._operation == Message::Command::Unknown)
1118 blockChainHeader._ackTypes |= Message::AckType::Persisted;
1121 pBuffer->setPosition(position);
1123 if (blockHeader._totalRemaining
1124 < blockChainHeader._commandIdLen
1125 + blockChainHeader._correlationIdLen
1126 + blockChainHeader._expirationLen
1127 + blockChainHeader._sowKeyLen
1128 + blockChainHeader._topicLen)
1130 std::ostringstream os;
1131 os <<
"Corrupted message found with invalid lengths. "
1132 <<
"Attempting to replay " << block_->_sequence
1133 <<
". Block sequence " << blockHeader._seq
1134 <<
", topic length " << blockChainHeader._topicLen
1135 <<
", data length " << blockHeader._totalRemaining
1136 <<
", command ID length " << blockChainHeader._commandIdLen
1137 <<
", correlation ID length " << blockChainHeader._correlationIdLen
1138 <<
", expiration length " << blockChainHeader._expirationLen
1139 <<
", sow key length " << blockChainHeader._sowKeyLen
1140 <<
", start " << start
1141 <<
", position " << position
1142 <<
", buffer size " << pBuffer->getSize();
1143 throw StoreException(os.str());
1148 _message.
setCommandEnum((Message::Command::Type)blockChainHeader._operation);
1150 | Message::AckType::Persisted);
1153 Block* current = block_;
1155 amps_uint64_t crcCalc = (amps_uint64_t)0ULL;
1157 char** tmpBuffers = (blockHeader._blocksToWrite > 1) ?
new char* [blockHeader._blocksToWrite - 1] : 0;
1158 size_t blockNum = 0;
1159 if (blockChainHeader._commandIdLen > 0)
1161 if (blockChainHeader._commandIdLen <= blockBytesRemaining)
1163 _message.
assignCommandId(pBuffer->getBytes(blockChainHeader._commandIdLen)._data,
1164 blockChainHeader._commandIdLen);
1165 blockBytesRemaining -= blockChainHeader._commandIdLen;
1169 tmpBuffers[blockNum] =
new char[blockChainHeader._commandIdLen];
1170 size_t totalLeft = blockChainHeader._commandIdLen;
1171 size_t totalRead = 0;
1175 readLen = blockBytesRemaining < totalLeft ?
1176 blockBytesRemaining : totalLeft;
1177 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1178 if (!(totalLeft -= readLen))
1182 if (!(current = current->_nextInChain))
1186 totalRead += readLen;
1189 pBuffer->setPosition(position);
1191 blockBytesRemaining -= readLen;
1192 _message.
assignCommandId(tmpBuffers[blockNum++], blockChainHeader._commandIdLen);
1194 blockHeader._totalRemaining -= blockChainHeader._commandIdLen;
1196 blockChainHeader._commandIdLen, crcCalc);
1198 if (blockChainHeader._correlationIdLen > 0)
1200 if (blockChainHeader._correlationIdLen <= blockBytesRemaining)
1203 pBuffer->getBytes(blockChainHeader._correlationIdLen)._data,
1204 blockChainHeader._correlationIdLen);
1205 blockBytesRemaining -= blockChainHeader._correlationIdLen;
1209 tmpBuffers[blockNum] =
new char[blockChainHeader._correlationIdLen];
1210 size_t totalLeft = blockChainHeader._correlationIdLen;
1211 size_t totalRead = 0;
1215 readLen = blockBytesRemaining < totalLeft ?
1216 blockBytesRemaining : totalLeft;
1217 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1218 if (!(totalLeft -= readLen))
1222 if (!(current = current->_nextInChain))
1226 totalRead += readLen;
1229 pBuffer->setPosition(position);
1231 blockBytesRemaining -= readLen;
1234 blockHeader._totalRemaining -= blockChainHeader._correlationIdLen;
1236 blockChainHeader._correlationIdLen, crcCalc);
1238 if (blockChainHeader._expirationLen > 0)
1240 if (blockChainHeader._expirationLen <= blockBytesRemaining)
1243 pBuffer->getBytes(blockChainHeader._expirationLen)._data,
1244 blockChainHeader._expirationLen);
1245 blockBytesRemaining -= blockChainHeader._expirationLen;
1249 tmpBuffers[blockNum] =
new char[blockChainHeader._expirationLen];
1250 size_t totalLeft = blockChainHeader._expirationLen;
1251 size_t totalRead = 0;
1255 readLen = blockBytesRemaining < totalLeft ?
1256 blockBytesRemaining : totalLeft;
1257 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1258 if (!(totalLeft -= readLen))
1262 if (!(current = current->_nextInChain))
1266 totalRead += readLen;
1269 pBuffer->setPosition(position);
1271 blockBytesRemaining -= readLen;
1272 _message.
assignExpiration(tmpBuffers[blockNum++], blockChainHeader._expirationLen);
1274 blockHeader._totalRemaining -= blockChainHeader._expirationLen;
1276 blockChainHeader._expirationLen, crcCalc);
1278 if (blockChainHeader._sowKeyLen > 0)
1280 if (blockChainHeader._sowKeyLen <= blockBytesRemaining)
1282 _message.
assignSowKey(pBuffer->getBytes(blockChainHeader._sowKeyLen)._data,
1283 blockChainHeader._sowKeyLen);
1284 blockBytesRemaining -= blockChainHeader._sowKeyLen;
1288 tmpBuffers[blockNum] =
new char[blockChainHeader._sowKeyLen];
1289 size_t totalLeft = blockChainHeader._sowKeyLen;
1290 size_t totalRead = 0;
1294 readLen = blockBytesRemaining < totalLeft ?
1295 blockBytesRemaining : totalLeft;
1296 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1297 if (!(totalLeft -= readLen))
1301 if (!(current = current->_nextInChain))
1305 totalRead += readLen;
1308 pBuffer->setPosition(position);
1310 blockBytesRemaining -= readLen;
1311 _message.
assignSowKey(tmpBuffers[blockNum++], blockChainHeader._sowKeyLen);
1313 blockHeader._totalRemaining -= blockChainHeader._sowKeyLen;
1314 crcCalc = _crc(_message.
getSowKey().
data(), blockChainHeader._sowKeyLen, crcCalc);
1316 if (blockChainHeader._topicLen > 0)
1318 if (blockChainHeader._topicLen <= blockBytesRemaining)
1320 _message.
assignTopic(pBuffer->getBytes(blockChainHeader._topicLen)._data,
1321 blockChainHeader._topicLen);
1322 blockBytesRemaining -= blockChainHeader._topicLen;
1326 tmpBuffers[blockNum] =
new char[blockChainHeader._topicLen];
1327 size_t totalLeft = blockChainHeader._topicLen;
1328 size_t totalRead = 0;
1332 readLen = blockBytesRemaining < totalLeft ?
1333 blockBytesRemaining : totalLeft;
1334 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1335 if (!(totalLeft -= readLen))
1339 if (!(current = current->_nextInChain))
1343 totalRead += readLen;
1346 pBuffer->setPosition(position);
1348 blockBytesRemaining -= readLen;
1349 _message.
assignTopic(tmpBuffers[blockNum++], blockChainHeader._topicLen);
1351 blockHeader._totalRemaining -= blockChainHeader._topicLen;
1352 crcCalc = _crc(_message.
getTopic().
data(), blockChainHeader._topicLen, crcCalc);
1354 if (blockHeader._totalRemaining > 0)
1356 if (blockHeader._totalRemaining <= blockBytesRemaining)
1358 if (blockChainHeader._flag == -1 || blockChainHeader._flag == SOW_DELETE_DATA)
1360 _message.assignData(
1361 pBuffer->getBytes(blockHeader._totalRemaining)._data,
1362 blockHeader._totalRemaining);
1364 blockHeader._totalRemaining, crcCalc);
1366 else if (blockChainHeader._flag == SOW_DELETE_FILTER)
1369 pBuffer->getBytes(blockHeader._totalRemaining)._data,
1370 blockHeader._totalRemaining);
1372 blockHeader._totalRemaining, crcCalc);
1374 else if (blockChainHeader._flag == SOW_DELETE_KEYS)
1377 pBuffer->getBytes(blockHeader._totalRemaining)._data,
1378 blockHeader._totalRemaining);
1380 blockHeader._totalRemaining, crcCalc);
1382 else if (blockChainHeader._flag == SOW_DELETE_BOOKMARK)
1385 pBuffer->getBytes(blockHeader._totalRemaining)._data,
1386 blockHeader._totalRemaining);
1388 blockHeader._totalRemaining, crcCalc);
1390 else if (blockChainHeader._flag == SOW_DELETE_BOOKMARK_CANCEL)
1393 pBuffer->getBytes(blockHeader._totalRemaining)._data,
1394 blockHeader._totalRemaining);
1396 blockHeader._totalRemaining, crcCalc);
1402 tmpBuffers[blockNum] =
new char[blockHeader._totalRemaining];
1403 size_t totalLeft = blockHeader._totalRemaining;
1404 size_t totalRead = 0;
1408 readLen = blockBytesRemaining < totalLeft ?
1409 blockBytesRemaining : totalLeft;
1410 pBuffer->copyBytes(tmpBuffers[blockNum] + totalRead, readLen);
1411 if (!(totalLeft -= readLen))
1415 if (!(current = current->_nextInChain))
1419 totalRead += readLen;
1422 pBuffer->setPosition(position);
1424 position += readLen;
1425 if (blockChainHeader._flag == -1 || blockChainHeader._flag == SOW_DELETE_DATA)
1427 _message.assignData(tmpBuffers[blockNum], blockHeader._totalRemaining);
1429 else if (blockChainHeader._flag == SOW_DELETE_FILTER)
1431 _message.
assignFilter(tmpBuffers[blockNum], blockHeader._totalRemaining);
1433 else if (blockChainHeader._flag == SOW_DELETE_KEYS)
1435 _message.
assignSowKeys(tmpBuffers[blockNum], blockHeader._totalRemaining);
1437 else if (blockChainHeader._flag == SOW_DELETE_BOOKMARK)
1439 _message.
assignBookmark(tmpBuffers[blockNum], blockHeader._totalRemaining);
1441 else if (blockChainHeader._flag == SOW_DELETE_BOOKMARK_CANCEL)
1443 _message.
assignBookmark(tmpBuffers[blockNum], blockHeader._totalRemaining);
1446 crcCalc = _crc(tmpBuffers[blockNum++], blockHeader._totalRemaining, crcCalc);
1451 if (crcCalc != blockHeader._crcVal || blockHeader._seq != block_->_sequence)
1453 std::ostringstream os;
1454 os <<
"Corrupted message found by CRC or sequence "
1455 <<
"Attempting to replay " << block_->_sequence
1456 <<
". Block sequence " << blockHeader._seq
1457 <<
", expiration length " << blockChainHeader._expirationLen
1458 <<
", sowKey length " << blockChainHeader._sowKeyLen
1459 <<
", topic length " << blockChainHeader._topicLen
1460 <<
", data length " << blockHeader._totalRemaining
1461 <<
", command ID length " << blockChainHeader._commandIdLen
1462 <<
", correlation ID length " << blockChainHeader._correlationIdLen
1463 <<
", flag " << blockChainHeader._flag
1464 <<
", expected CRC " << blockHeader._crcVal
1465 <<
", actual CRC " << crcCalc
1466 <<
", start " << start
1467 <<
", position " << position
1468 <<
", buffer size " << pBuffer->getSize();
1469 for (Block* block = block_; block; block = block->_nextInChain)
1471 os <<
"\n BLOCK " << block->_offset;
1475 for (amps_uint32_t i = 0; i < blockNum; ++i)
1477 delete[] tmpBuffers[i];
1479 delete[] tmpBuffers;
1481 throw StoreException(os.str());
1484 replayer_.execute(_message);
1488 for (amps_uint32_t i = 0; i < blockNum; ++i)
1490 delete[] tmpBuffers[i];
1492 delete[] tmpBuffers;
1498 void expandBlocks(Block* blocks_,
size_t location_, Block* first_,
1499 BlockHeader blockHeader_,
1500 Block** pFreeList_, amps_uint32_t* pFreeCount_,
1504 Block* current = first_;
1507 amps_uint32_t oldTotalRemaining = blockHeader_._totalRemaining;
1508 blockHeader_._totalRemaining -= 64;
1512 amps_uint32_t blocksNeeded = blockHeader_._totalRemaining
1514 + (blockHeader_._totalRemaining
1521 size_t endBlockSize = oldTotalRemaining % blockSize;
1524 endBlockSize = blockSize;
1526 size_t endOfData = 0;
1528 amps_uint64_t crcVal = blockHeader_._crcVal;
1529 blockHeader_._crcVal = 0;
1531 std::stack<Block*> blocksUsed;
1532 for (amps_uint32_t i = 1; i < blocksNeeded; ++i)
1534 blocksUsed.push(current);
1535 current->_sequence = blockHeader_._seq;
1536 if (i >= blockHeader_._blocksToWrite)
1538 if (i == blockHeader_._blocksToWrite)
1540 endOfData = current->_offset + endBlockSize;
1542 current->_nextInChain = *pFreeList_;
1544 *pFreeList_ = (*pFreeList_)->_nextInList;
1548 current->_nextInChain = current->_nextInList;
1549 if (current->_nextInChain)
1551 if (current->_offset + blockSize < pBuffer_->getSize())
1553 current->_nextInChain->setOffset(current->_offset
1558 current->_nextInChain->setOffset(blockSize);
1563 current->_nextInChain = blocks_[1].init(1, blockSize);
1565 if (current->_nextInChain == *pFreeList_)
1567 *pFreeList_ = (*pFreeList_)->_nextInList;
1572 for (Block* free = *pFreeList_; free;
1573 free = free->_nextInList)
1575 if (free->_nextInList == current->_nextInChain)
1577 free->_nextInList = free->_nextInList->_nextInList;
1584 current->_nextInList = 0;
1585 current = current->_nextInChain;
1588 blockHeader_._blocksToWrite = blocksNeeded;
1590 current->_nextInList = 0;
1591 current->_sequence = blockHeader_._seq;
1601 while (current != first_)
1603 size_t chunkBytesAvail = endOfData > location_
1604 ? endOfData - location_
1606 if (chunkBytesAvail < dataBytes)
1613 pBuffer_->copyBytes(current->_offset
1618 chunkBytesAvail = dataBytes - chunkBytesAvail;
1619 endOfData = pBuffer_->getSize() - chunkBytesAvail;
1626 endOfData -= dataBytes;
1632 blockHeader_._nextInChain = (current->_nextInChain
1633 ? current->_nextInChain->_offset
1634 : (amps_uint64_t)0);
1636 pBuffer_->setPosition(current->_offset);
1637 pBuffer_->putBytes((
const char*)&blockHeader_,
sizeof(BlockHeader));
1638 current = blocksUsed.top();
1643 pBuffer_->copyBytes(first_->_offset
1649 blockHeader_._crcVal = crcVal;
1650 blockHeader_._nextInChain = first_->_nextInChain->_offset;
1654 pBuffer_->setPosition(location_ + (
sizeof(amps_uint32_t) * 2)
1655 + (
sizeof(amps_uint64_t) * 2) );
1660 BlockChainHeader chainHeader;
1661 pBuffer_->copyBytes((
char*)&chainHeader,
1662 sizeof(amps_uint32_t) * 8);
1664 pBuffer_->setPosition(location_);
1665 pBuffer_->putBytes((
const char*)&blockHeader_,
sizeof(BlockHeader));
1666 pBuffer_->putBytes((
const char*)&chainHeader,
sizeof(BlockChainHeader));
1669 void chooseCRC(
bool isFile)
1678 _crc = AMPS::CRC<0>::crcNoSSE;
1680 if (AMPS::CRC<0>::isSSE42Enabled())
1682 _crc = AMPS::CRC<0>::crc;
1686 _crc = AMPS::CRC<0>::crcNoSSE;
1691 static amps_uint64_t noOpCRC(
const char*,
size_t, amps_uint64_t)
1697 mutable BlockStore _blockStore;
1701 Block* _metadataBlock;
1703 amps_uint64_t _maxDiscarded;
1705 #if __cplusplus >= 201103L || _MSC_VER >= 1900
1706 std::atomic<amps_uint64_t> _lastSequence;
1708 volatile amps_uint64_t _lastSequence;
1711 AMPS_ATOMIC_TYPE _stored;
1716 typedef amps_uint64_t (*CRCFunction)(
const char*, size_t, amps_uint64_t);
Provides AMPS::BlockStore, a class for storing Blocks of a fixed size into a Buffer implementation.
Provides AMPS::Buffer, an abstract base class used by the store implementations in the AMPS client.
AMPSDLL amps_uint64_t amps_message_get_field_uint64(amps_handle message, FieldId field)
Gets the unsigned 64-bit int value of a header field in an AMPS message.
Core type, function, and class declarations for the AMPS C++ client.
Base class for all exceptions in AMPS.
Definition: AMPSException.hpp:41
Used as a base class for other stores in the AMPS C++ client, this is an implementation of StoreImpl ...
Definition: BlockPublishStore.hpp:61
amps_uint32_t getBlockDataSize()
Return the size left in a block for data when it has a header in it.
Definition: BlockPublishStore.hpp:179
virtual void discardUpTo(amps_uint64_t index_)
Remove all messages with an index up to and including index_.
Definition: BlockPublishStore.hpp:498
static amps_uint32_t getBlockChainHeaderSize()
Block chain header is operation, command id length, correlation id length, expiration length,...
Definition: BlockPublishStore.hpp:163
BlockPublishStore(Buffer *buffer_, amps_uint32_t blocksPerRealloc_=1000, bool isFile_=false, bool errorOnPublishGap_=false, amps_uint32_t blockSize_=DEFAULT_BLOCK_SIZE)
Create a BlockPublishStore using buffer_, that grows by blocksPerRealloc_ blocks when it must grow.
Definition: BlockPublishStore.hpp:200
void replay(StoreReplayer &replayer_)
Replay all messages in the Store onto the given StoreReplayer.
Definition: BlockPublishStore.hpp:561
amps_uint64_t getLowestUnpersisted() const
Get the oldest unpersisted message sequence in the store.
Definition: BlockPublishStore.hpp:699
size_t unpersistedCount() const
Method to return the count of messages that currently in the Store because they have not been discard...
Definition: BlockPublishStore.hpp:642
virtual void flush(long timeout_)
Method to wait for the Store to discard everything that has been stored up to the point in time when ...
Definition: BlockPublishStore.hpp:656
bool replaySingle(StoreReplayer &replayer_, amps_uint64_t index_)
Replay one message in the Store onto the given StoreReplayer.
Definition: BlockPublishStore.hpp:593
static amps_uint32_t getBlockHeaderSize()
Block header is number of blocks, total length, sequence number, crc, next in chain offset.
Definition: BlockPublishStore.hpp:153
amps_uint64_t store(const Message &message_, bool assignSequence_)
Store a given message that will be delivered to AMPS.
Definition: BlockPublishStore.hpp:266
Constants
Default constant values for BlockPublishStore.
Definition: BlockPublishStore.hpp:80
amps_uint32_t getBlockSize()
Return the size left in a block for data when it has a header in it.
Definition: BlockPublishStore.hpp:171
amps_uint64_t getLastPersisted(void)
Get the last persisted sequence number.
Definition: BlockPublishStore.hpp:711
virtual amps_uint64_t store(const Message &message_)
Store a given message that will be delivered to AMPS.
Definition: BlockPublishStore.hpp:251
virtual ~BlockPublishStore()
Destructor that cleans up the buffer and other associated memory.
Definition: BlockPublishStore.hpp:241
Used as metadata for each block in a Buffer.
Definition: BlockStore.hpp:75
void signalAll()
Signal lock waiters.
Definition: BlockStore.hpp:219
void putAll(Block *block_)
Return all Blocks starting with the given Block to the free list.
Definition: BlockStore.hpp:449
Block * front() const
Get the first used block in the store.
Definition: BlockStore.hpp:259
Block * back() const
Get the last used block in the store.
Definition: BlockStore.hpp:269
void addBlocks(Block *blockArray_)
Allow users to create Block arrays during recovery that are tracked for cleanup here with all other B...
Definition: BlockStore.hpp:304
void setEndOfUsedList(Block *block_)
Allow containing classes to initialize the used list in recovery.
Definition: BlockStore.hpp:295
void setUsedList(Block *block_)
Allow containing classes to initialize the used list in recovery.
Definition: BlockStore.hpp:287
Block * resizeBuffer(size_t size_, amps_uint32_t *pNewBlocks_)
Resize the buffer to the requested size, returning all new space.
Definition: BlockStore.hpp:537
Block * get(amps_uint32_t numBlocksInChain_)
Get the requested number of Blocks as a chain from the free list.
Definition: BlockStore.hpp:314
void setFreeList(Block *block_, amps_uint32_t freeCount_)
Allow containing classes to initialize the free list in recovery.
Definition: BlockStore.hpp:278
Buffer * getBuffer()
Return the buffer underlying the store for direct write/read.
Definition: BlockStore.hpp:677
void setResizeHandler(ResizeHandler resizeHandler_, void *userData_)
Set a resize handler that is called with the new total size of the Buffer.
Definition: BlockStore.hpp:249
amps_uint32_t setBlockHeaderSize(amps_uint32_t blockHeaderSize_)
Set the size to use for the header for all Blocks.
Definition: BlockStore.hpp:663
amps_uint32_t setBlockSize(amps_uint32_t blockSize_)
Set the size to use for all Blocks.
Definition: BlockStore.hpp:648
void init()
Initialize, assuming that _buffer has no existing information.
Definition: BlockStore.hpp:481
amps_uint32_t getBlockSize() const
Get the size of each Block, as set in the constructor.
Definition: BlockStore.hpp:189
void wait()
Wait for a signal.
Definition: BlockStore.hpp:226
void put(Block *block_)
Return the given chain of Blocks to the free list for reuse.
Definition: BlockStore.hpp:383
Abstract base class for implementing a buffer to be used by a StoreImpl for storage of publish messag...
Definition: Buffer.hpp:41
virtual void putUint64(amps_uint64_t ui_)=0
Put an amps_uint64_t value into the buffer at the current position and advance past it.
virtual void putUint32(amps_uint32_t i_)=0
Put an unsigned 32-bit int value into the buffer at the current position and advance past the end of ...
virtual size_t getSize() const =0
Get the current size of the Buffer in bytes.
virtual amps_uint32_t getUint32()=0
Get the unsigned 32-bit int value at the current buffer position and advance past it.
virtual void putBytes(const char *data_, size_t dataLength_)=0
Put the given length of bytes in data into the buffer at the current position and advance past them.
virtual void setPosition(size_t position_)=0
Set the buffer postion to a location.
Field represents the value of a single field in a Message.
Definition: Field.hpp:88
size_t len() const
Returns the length of the data underlying this field.
Definition: Field.hpp:298
const char * data() const
Returns the (non-null-terminated) data underlying this field.
Definition: Field.hpp:291
Message encapsulates a single message sent to or received from an AMPS server, and provides methods f...
Definition: Message.hpp:518
Message & assignExpiration(const std::string &v)
Assigns the value of the Expiration header for this Message without copying.
Definition: Message.hpp:1345
void getRawFilter(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the Filter header of self in the underlyin...
Definition: Message.hpp:1346
Field getBookmark() const
Retrieves the value of the Bookmark header of the Message as a Field which references the underlying ...
Definition: Message.hpp:1234
Field getCommandId() const
Retrieves the value of the CommandId header of the Message as a Field which references the underlying...
Definition: Message.hpp:1342
Field getData() const
Returns the data from this message.
Definition: Message.hpp:1500
Message & assignOptions(const std::string &v)
Assigns the value of the Options header for this Message without copying.
Definition: Message.hpp:1397
Field getCorrelationId() const
Retrieves the value of the CorrelationId header of the Message as a Field which references the underl...
Definition: Message.hpp:1344
Field getSowKeys() const
Retrieves the value of the SowKeys header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1465
Field getExpiration() const
Retrieves the value of the Expiration header of the Message as a Field which references the underlyin...
Definition: Message.hpp:1345
Field getFilter() const
Retrieves the value of the Filter header of the Message as a Field which references the underlying bu...
Definition: Message.hpp:1346
Message & assignFilter(const std::string &v)
Assigns the value of the Filter header for this Message without copying.
Definition: Message.hpp:1346
Message & setSequence(const std::string &v)
Sets the value of the Sequence header for this Message.
Definition: Message.hpp:1462
Message & setAckTypeEnum(unsigned ackType_)
Encode self's "ack type" field from a bitmask of values from AckType.
Definition: Message.hpp:1223
unsigned getAckTypeEnum() const
Decode self's "ack type" field and return the corresponding bitmask of values from AckType.
Definition: Message.hpp:1200
Message & assignSowKeys(const std::string &v)
Assigns the value of the SowKeys header for this Message without copying.
Definition: Message.hpp:1465
void getRawSowKey(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the SowKey header of self in the underlyin...
Definition: Message.hpp:1464
void getRawCommandId(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the CommandId header of self in the underl...
Definition: Message.hpp:1342
void getRawExpiration(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the Expiration header of self in the under...
Definition: Message.hpp:1345
Command::Type getCommandEnum() const
Decode self's "command" field and return one of the values from Command.
Definition: Message.hpp:1268
void getRawBookmark(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the Bookmark header of self in the underly...
Definition: Message.hpp:1234
Field getSowKey() const
Retrieves the value of the SowKey header of the Message as a Field which references the underlying bu...
Definition: Message.hpp:1464
Message & assignTopic(const std::string &v)
Assigns the value of the Topic header for this Message without copying.
Definition: Message.hpp:1489
void getRawTopic(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the Topic header of self in the underlying...
Definition: Message.hpp:1489
Message & setCommandEnum(Command::Type command_)
Set self's "command" field from one of the values in Command.
Definition: Message.hpp:1328
Message & assignCommandId(const std::string &v)
Assigns the value of the CommandId header for this Message without copying.
Definition: Message.hpp:1342
Field getTopic() const
Retrieves the value of the Topic header of the Message as a Field which references the underlying buf...
Definition: Message.hpp:1489
void getRawCorrelationId(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the CorrelationId header of self in the un...
Definition: Message.hpp:1344
Message & assignCorrelationId(const std::string &v)
Assigns the value of the CorrelationId header for this Message without copying.
Definition: Message.hpp:1344
Message & assignBookmark(const std::string &v)
Assigns the value of the Bookmark header for this Message without copying.
Definition: Message.hpp:1234
void getRawSowKeys(const char **dataptr, size_t *sizeptr) const
Modifies the passed in arguments to reference the value of the SowKeys header of self in the underlyi...
Definition: Message.hpp:1465
Field getOptions() const
Retrieves the value of the Options header of the Message as a Field which references the underlying b...
Definition: Message.hpp:1356
Message & assignSowKey(const std::string &v)
Assigns the value of the SowKey header for this Message without copying.
Definition: Message.hpp:1464
Abstract base class for storing published messages for an HA publisher client.
Definition: ampsplusplus.hpp:1098
static amps_uint64_t getUnsetSequence()
Method to return the value used to represent no such sequence.
Definition: ampsplusplus.hpp:1167
Abstract base class for replaying a publish message.
Definition: ampsplusplus.hpp:1070
virtual void execute(Message &message_)=0
Called by implementations of Store to replay a message from the store.