Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance bmqtool to handle poison pill message dumps #288

Merged
merged 28 commits into from
May 29, 2024

Conversation

alexander-e1off
Copy link
Collaborator

@alexander-e1off alexander-e1off commented May 14, 2024

Enhance bmqtool to add ability to read and replay the poison pill message dumped in the file by the broker, so that consumers can debug their applications.

Proposed changes
Format of the dump file is defined in QueueEngineUtil::dumpMessageInTempfile() method. Since message properties are dumped as a string, it is impossible to parse them properly. Thus, it is proposed to enhance dump, and add properties hexdump (similar way as payload).

Add new command to bmqtool:
load-post uri=<uri> file=<path-to-dump-file>
Message content is loaded from dump file and posted to the specified uri.

Testing performed
Unit tests for parsing of dump file are added.
Manually with bmqtool simulated poison pill conditions and created dumps with and w/o message properties. Then tested these dumps with load-post commands.

alexander-e1off and others added 4 commits May 10, 2024 18:26
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@alexander-e1off alexander-e1off requested a review from a team as a code owner May 14, 2024 10:15
@alexander-e1off alexander-e1off changed the title Enhance bmqtool to read poison pill message dumps WIP: Enhance bmqtool to read poison pill message dumps May 14, 2024
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@678098 678098 self-requested a review May 15, 2024 11:31
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@alexander-e1off alexander-e1off changed the title WIP: Enhance bmqtool to read poison pill message dumps Enhance bmqtool to read poison pill message dumps May 15, 2024
@@ -474,11 +578,8 @@ void Interactive::processCommand(const PostCommand& command, bool hasMPs)

if (hasMPs) {
d_session_p->loadMessageProperties(&properties);

for (size_t j = 0; j < command.messageProperties().size(); ++j) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand what is the purpose of this for cycle. Inside InputUtil::populateProperties() there is also for cycle which is used to process properties. Removed it.

@alexander-e1off alexander-e1off changed the title Enhance bmqtool to read poison pill message dumps Enhance bmqtool to handle poison pill message dumps May 15, 2024
Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments

src/applications/bmqtool/bmqtoolcmd.xsd Outdated Show resolved Hide resolved
@@ -149,11 +150,55 @@ void InputUtil::populateProperties(
BSLS_ASSERT_SAFE(0 == result);
} break; // BREAK

case MessagePropertyType::E_INT: {
case MessagePropertyType::E_INT32: {
BSLA_MAYBE_UNUSED int result =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, and in other places:

Suggested change
BSLA_MAYBE_UNUSED int result =
BSLA_MAYBE_UNUSED const int result =

@@ -149,11 +150,55 @@ void InputUtil::populateProperties(
BSLS_ASSERT_SAFE(0 == result);
} break; // BREAK

case MessagePropertyType::E_INT: {
case MessagePropertyType::E_INT32: {
BSLA_MAYBE_UNUSED int result =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be also good to replace result -> rc to make it shorter and easier everywhere


case MessagePropertyType::E_BOOL: {
bool boolValue;
bsl::istringstream(value) >> bsl::boolalpha >> boolValue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 166: uninitialized bool
Line 167: try to read bool value without check that the read reads something
Line 168: setting possibly random value of this bool as property

Maybe something like this will work:

bsl::stringstream iss(value);
BSLA_MAYBE_UNUSED const bool readSuccess = (iss >> bsl::boolalpha >> boolValue);
BSLS_ASSERT(readSuccess);
...

@@ -149,11 +150,55 @@ void InputUtil::populateProperties(
BSLS_ASSERT_SAFE(0 == result);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think BSLS_ASSERT_SAFE is not enough here, since we deal with user provided data here. When compiled as Release, we still want to have these values checks.

Consider using BSLS_ASSERT instead

@@ -80,6 +88,13 @@ struct InputUtil {
bsl::string* error,
const bsl::string& jsonInput);

/// Decode hexdump produced by bdlb::Print::hexDump() into binary format.
/// Read hexdump from the specified `in` and write binary into th specified
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Read hexdump from the specified `in` and write binary into th specified
/// Read hexdump from the specified `in` and write binary into the specified

bool loadMessageContentFromFile(
bsl::vector<bsl::string>* payload,
bsl::vector<MessageProperty>* messageProperties,
bsl::ostream& errorDescription,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some places, bsl::string * is passed to return error messages, here bsl::ostream.
Might be good to unify it. I believe passing bsl::ostream might be better, since it will be easier to output variable parameters like tokens, strings etc without intermediate mwcu::MemOutStream. What do you think?

&parseError)) {
errorDescription << "Message properties parse error: "
<< parseError;
return false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, and in other places below

Suggested change
return false;
return false; // RETURN

@@ -900,7 +1027,15 @@ int Interactive::mainLoop()
if (mps) {
hasMPs = keys.find(mps->name()) != keys.cend();
}
processCommand(command, hasMPs);

bool commandValid = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool commandValid = true;
bool commandIsValid = true;

}
if (commandValid) {
processCommand(command, hasMPs);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log something if the command is not valid?

@alexander-e1off alexander-e1off marked this pull request as draft May 16, 2024 06:36
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@alexander-e1off
Copy link
Collaborator Author

@678098 What do you think about the following idea. To avoid reinventing the wheel during dump/parse message properties and keep existing functionality (human readable text) we can add properties hexdump using existing functionality:

  • During the message dump to the file, in addition to properties print, serialize properties into blob and hexdump them to the file the same way as payload is dumped;
  • When reading dump from the file, decode hexdump to binary and deserialize message properties;

In this case we keep dump file human readable (just one more hexdump will be added) and no need to create new format of properties dump. Below is simplified prototype

            // During message dump add properties hexdump
            bdlbb::PooledBlobBufferFactory bufferFactory(1024);
            const bdlbb::Blob& blob = properties.streamOut(&bufferFactory);
            dumpFileStream << bdlbb::BlobUtilHexDumper(&blob); 
        

            // When reading dump from the file
            mwcu::MemOutStream  binaryStream;
            bsl::istringstream inpStream(hexdumpStream.str());
            InputUtil::decodeHexDump(&binaryStream, inpStream)

            bdlbb::Blob resultBlob(&bufferFactory);
            bdlbb::BlobUtil::append(&resultBlob, binaryStream.str().data(), binaryStream.str().length());

            bmqa::MessageProperties properties;
            properties.streamIn(resultBlob);

Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@alexander-e1off alexander-e1off marked this pull request as ready for review May 24, 2024 16:00
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
@alexander-e1off
Copy link
Collaborator Author

alexander-e1off commented May 24, 2024

@678098 Would you please look again, I've rolled back previous solution and implemented new one, also added unit tests. Thank you.

@678098
Copy link
Collaborator

678098 commented May 24, 2024

@678098 Would you please look again, I've rolled back previous solution and implemented new one, also added unit tests. Thanks you.

Hi @alexander-e1off, thanks for the changes! Will look soon

Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, a few smaller suggestions

Comment on lines 101 to 102
<element name='uri' type='string'/>
<element name='file' type='string'/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<element name='uri' type='string'/>
<element name='file' type='string'/>
<element name='uri' type='string'/>
<element name='file' type='string'/>


while (bsl::getline(in, line)) {
if (line.empty()) {
break; // stop at the end of hexdump (empty line)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
break; // stop at the end of hexdump (empty line)
// stop at the end of hexdump (empty line)
break; // BREAK

bsl::istream& in,
bslma::Allocator* allocator);

/// Load message content from the specified `file` (created by
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Load message content from the specified `file` (created by
/// Load message content from the specified `filePath` (created by

Comment on lines 19 to 30
// BMQ
#include <bdlbb_pooledblobbufferfactory.h>
#include <bmqa_messageproperties.h>
#include <mwcu_memoutstream.h>
#include <mwcu_tempfile.h>

// BDE
#include <bdlbb_blob.h>
#include <bdlbb_blobutil.h>

// TEST DRIVER
#include <mwctst_testhelper.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// BMQ
#include <bdlbb_pooledblobbufferfactory.h>
#include <bmqa_messageproperties.h>
#include <mwcu_memoutstream.h>
#include <mwcu_tempfile.h>
// BDE
#include <bdlbb_blob.h>
#include <bdlbb_blobutil.h>
// TEST DRIVER
#include <mwctst_testhelper.h>
// BMQ
#include <bmqa_messageproperties.h>
// MWC
#include <mwcu_memoutstream.h>
#include <mwcu_tempfile.h>
// BDE
#include <bdlbb_blob.h>
#include <bdlbb_blobutil.h>
#include <bdlbb_pooledblobbufferfactory.h>
// TEST DRIVER
#include <mwctst_testhelper.h>

@@ -159,6 +159,12 @@ void Interactive::printHelp()
<< " - 'batch-post' command requires 'uri' argument, "
"all the rest are optional"
<< bsl::endl
<< bsl::endl
<< " load-post uri=\"bmq://bmq.test.persistent.priority/qqq\" "
"file=[\"message.dump\"]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to specify file path in [] brackets? It is the same string type as uri, right?


BALL_LOG_INFO << "--> Loading and posting message: " << command;

int rc;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be moved and const initialized in place below

Suggested change
int rc;

}

// Post
rc = d_session_p->post(eventBuilder.messageEvent());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rc = d_session_p->post(eventBuilder.messageEvent());
const int rc = d_session_p->post(eventBuilder.messageEvent());

Signed-off-by: Aleksandr Ivanov <aivanov71@bloomberg.net>
Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@alexander-e1off alexander-e1off merged commit 0636f8f into bloomberg:main May 29, 2024
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants