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

fix: duplicate meta key read #2744

Merged

Conversation

wangshao1
Copy link
Collaborator

@wangshao1 wangshao1 commented Jun 19, 2024

fix bugs mentioned in #2735

Summary by CodeRabbit

  • New Features

    • Added support for prefetching metadata in various Redis operations, enhancing performance and efficiency.
  • Refactor

    • Updated Redis methods across different data structures (Strings, Hashes, Lists, Sets, Zsets, Streams) to accept a prefetch_meta parameter, optimizing metadata handling.
    • Improved logic in key existence checks and expiration handling.
  • Bug Fixes

    • Ensured consistency with Redis implementation by setting exists = true and returning Status::OK() in specific conditions.
  • Performance Improvements

    • Enhanced the flow of operations by incorporating prefetch metadata, leading to more efficient handling of Redis commands.

@github-actions github-actions bot added the ☢️ Bug Something isn't working label Jun 19, 2024
Copy link

coderabbitai bot commented Jun 19, 2024

Walkthrough

The changes introduce a std::string&& prefetch_meta parameter to several methods in the Redis class across different data structure modules. This enhancement aims to improve efficiency in handling meta information related to expiration, deletion, persistence, and time-to-live operations, adding consistency and optimization across various Redis data types like Strings, Hashes, Lists, Sets, Zsets, and Streams.

Changes

File Path Change Summary
src/storage/src/redis.h Added std::string&& prefetch_meta parameter to multiple Redis class methods for expiration, deletion, persistence, TTL, and cardinality operations.
src/storage/src/redis_hashes.cc Updated Redis class methods for Hashes to include std::string&& prefetch_meta parameter for handling meta information.
src/storage/src/redis_lists.cc Added std::string&& prefetch_meta parameter to Redis class methods for Lists, affecting expiration, deletion, persistence, and TTL operations.
src/storage/src/redis_sets.cc Updated Redis class methods for Sets to accept an additional std::string&& prefetch_meta parameter for enhanced meta handling.
src/storage/src/redis_streams.cc Modified Redis class methods for Streams to include std::string&& prefetch_meta for stream processing and metadata handling.
src/storage/src/redis_strings.cc Refactored Redis class methods for Strings to accept std::string&& prefetch_meta parameter; improved consistency and meta value handling.
src/storage/src/redis_zsets.cc Enhanced Zset-related methods in the Redis class by adding std::string&& prefetch_meta; reorganized variable declarations and initialization.
src/storage/src/storage.cc Updated Storage::MSetnx logic to directly check for key existence using the IsExist method rather than retrieving and checking the value.

Poem

🐇

In the land of Redis, with keys held tight,
Meta flows swift with newfound might.
Prefetch dreams and TTL gleams,
Through Hashes, Lists, and Streams.
Efficiency whispers, a silent delight,
In “storage” we code, from morning till night.
The rabbit cheers with coding spree,
For optimizations set us free! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

Outside diff range and nitpick comments (1)
src/storage/src/redis_streams.cc (1)

Line range hint 178-187: Consider handling the potential exception from std::move when prefetch_meta is empty.

The use of std::move(prefetch_meta) directly in the function call to GetStreamMeta on line 187 could lead to unexpected behavior if prefetch_meta is empty or not properly initialized. Consider adding a check or ensuring that prefetch_meta is always valid when passed to this function.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e7edec6 and 8d838fc.

Files selected for processing (8)
  • src/storage/src/redis.h (7 hunks)
  • src/storage/src/redis_hashes.cc (6 hunks)
  • src/storage/src/redis_lists.cc (6 hunks)
  • src/storage/src/redis_sets.cc (6 hunks)
  • src/storage/src/redis_streams.cc (4 hunks)
  • src/storage/src/redis_strings.cc (15 hunks)
  • src/storage/src/redis_zsets.cc (6 hunks)
  • src/storage/src/storage.cc (1 hunks)
Additional comments not posted (11)
src/storage/src/redis.h (3)

120-149: The addition of the std::string&& prefetch_meta parameter to the expiration, deletion, and TTL methods is a significant change aimed at improving metadata handling efficiency. Ensure that all callers of these methods are updated to pass this new parameter correctly.

Verification successful

All instances of the modified methods in src/storage/src/redis.h have been updated to pass the new parameter std::string&& prefetch_meta correctly.

  • src/storage/src/redis.h
  • src/storage/src/redis_zsets.cc
  • src/storage/src/redis_streams.cc
  • src/storage/src/redis_strings.cc
  • src/storage/src/redis_sets.cc
  • src/storage/src/redis_lists.cc
  • src/storage/src/redis_hashes.cc
  • src/storage/src/storage.cc
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify all function calls to modified methods match the new signature.

# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type cpp $'StringsExpire|HashesExpire|ListsExpire|ZsetsExpire|SetsExpire|StringsDel|HashesDel|ListsDel|ZsetsDel|SetsDel|StreamsDel|StringsExpireat|HashesExpireat|ListsExpireat|SetsExpireat|ZsetsExpireat|StringsPersist|HashesPersist|ListsPersist|ZsetsPersist|SetsPersist|StringsTTL|HashesTTL|ListsTTL|ZsetsTTL|SetsTTL'

Length of output: 8999


326-326: Updates to the XRange and GetStreamMeta methods to include a std::string&& prefetch_meta parameter are crucial for stream processing efficiency. It's important to validate that these changes integrate seamlessly with existing stream-related functionalities and that they contribute positively to performance metrics.

Also applies to: 336-336


272-272: The LLen method now includes a std::string&& prefetch_meta parameter. Verify that this parameter is being used effectively within the method and that its addition does not introduce any performance or functionality issues.

Verification successful

The implementation of the LLen method in src/storage/src/redis_lists.cc shows that the prefetch_meta parameter is effectively utilized. Specifically, it is moved into meta_value and used to determine if additional database operations are necessary. This approach ensures that if prefetch_meta is provided, redundant database reads are avoided, which could potentially improve performance.

  • src/storage/src/redis_lists.cc: The LLenmethod uses theprefetch_meta` parameter effectively.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Check all calls to `LLen` for correct usage of the new signature.
rg --type cpp 'LLen'

Length of output: 2567



Script:

#!/bin/bash
# Extract the implementation of the `LLen` method from `src/storage/src/redis_lists.cc`.
ast-grep --lang cpp --pattern $'Status Redis::LLen(const Slice& key, uint64_t* len, std::string&& prefetch_meta) {
  $$$
}' src/storage/src/redis_lists.cc

Length of output: 155



Script:

#!/bin/bash
# Search for the `LLen` method definition and implementation across the entire repository.
rg 'Status Redis::LLen' --type cpp

Length of output: 150



Script:

#!/bin/bash
# Extract the full implementation of the `LLen` method from `src/storage/src/redis_lists.cc`.
sed -n '/Status Redis::LLen(const Slice& key, uint64_t* len, std::string&& prefetch_meta)/,/^}/p' src/storage/src/redis_lists.cc

Length of output: 130



Script:

#!/bin/bash
# Extract the implementation of the `LLen` method from `src/storage/src/redis_lists.cc`.
ast-grep --lang cpp --pattern $'function_definition
 name: "LLen"
 body: $_
' src/storage/src/redis_lists.cc

Length of output: 454



Script:

#!/bin/bash
# Search for the `LLen` method implementation in `src/storage/src/redis_lists.cc` and surrounding lines.
rg -A 20 -B 5 'Status Redis::LLen' src/storage/src/redis_lists.cc

Length of output: 1078

src/storage/src/redis_lists.cc (2)

1113-1126: Review timestamp handling in ListsExpireat.
[REFACTOR_SUGGESTion]

- if (timestamp > 0) {
+ // Set a new expiration time if a positive timestamp is provided
+ if (timestamp > 0 && timestamp > GetCurrentTime()) {
  parsed_lists_meta_value.SetEtime(static_cast<uint64_t>(timestamp));
  return db_->Put(default_write_options_, handles_[kMetaCF], base_meta_key.Encode(), meta_value);
} else {
  parsed_lists_meta_value.InitialMetaValue();
  return db_->Put(default_write_options_, handles_[kMetaCF], base_meta_key.Encode(), meta_value);
}

Ensure that the timestamp is in the future before setting it as the new expiration time to avoid logical errors.


1081-1094: Check the deletion logic in ListsDel.

Verify through additional unit tests or integration tests that the deletion logic behaves as expected when prefetch_meta is provided and when it is not.

src/storage/src/redis_sets.cc (1)

1370-1383: Check for potential data races or concurrency issues.

The method SetsDel modifies the database state based on possibly stale metadata. Ensure that there are proper locking mechanisms in place to handle concurrent modifications to the same key.

Verification successful

The search results show that the SetsDel method in src/storage/src/redis_sets.cc does use a ScopeRecordLock to handle concurrent access to the key. This indicates that there are proper locking mechanisms in place to manage concurrent modifications to the same key.

  • src/storage/src/redis_sets.cc:1372: The ScopeRecordLock l(lock_mgr_, key); line ensures that the key is locked during the execution of SetsDel.

Given this evidence, the necessary locking mechanisms appear to be implemented correctly.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify locking mechanisms for the SetsDel operation

# Test: Search for lock usage around SetsDel calls. Expect: Proper locking mechanisms.
rg --type cpp $'ScopeRecordLock l(lock_mgr_, key);\\n.*\\n.*SetsDel'

Length of output: 259



Script:

#!/bin/bash
# Description: Verify locking mechanisms for the SetsDel operation

# Test: Search for lock usage around SetsDel calls. Expect: Proper locking mechanisms.
rg --multiline --type cpp $'ScopeRecordLock l(lock_mgr_, key);\n.*\n.*SetsDel'

Length of output: 77



Script:

#!/bin/bash
# Description: Verify locking mechanisms for the SetsDel operation

# Test: Search for SetsDel calls and examine surrounding code for locking mechanisms.
rg --multiline --type cpp $'SetsDel\(.*\)' -A 5 -B 5

Length of output: 3075

src/storage/src/redis_zsets.cc (5)

1598-1611: Refactor duplicate error handling code.
[REFACTOR_SUGGESTion]

- if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) {
-   if (ExpectedStale(meta_value)) {
-     s = Status::NotFound();
-   } else {
-     return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(meta_value)));
-   }
- }
+ if (!HandleMetaValueCheck(s, meta_value, DataType::kZSets, key)) {
+   return s;
+ }

Consider extracting the repeated pattern of checking meta_value and handling errors into a helper function HandleMetaValueCheck to reduce code duplication and improve maintainability.

Also applies to: 1611-1611


1632-1645: Refactor duplicate error handling code.
[REFACTOR_SUGGESTion]

- if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) {
-   if (ExpectedStale(meta_value)) {
-     s = Status::NotFound();
-   } else {
-     return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast[int](DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(meta_value)));
-   }
- }
+ if (!HandleMetaValueCheck(s, meta_value, DataType::kZSets, key)) {
+   return s;
+ }

Same suggestion as above to extract the repeated pattern of checking meta_value and handling errors into a helper function HandleMetaValueCheck to reduce code duplication and improve maintainability.

Also applies to: 1645-1645


1664-1677: Refactor duplicate error handling code.
[REFACTOR_SUGGESTion]

- if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) {
-   if (ExpectedStale(meta_value)) {
-     s = Status::NotFound();
-   } else {
-     return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast[int](DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(meta_value)));
-   }
- }
+ if (!HandleMetaValueCheck(s, meta_value, DataType::kZSets, key)) {
+   return s;
+ }

Same suggestion as above to extract the repeated pattern of checking meta_value and handling errors into a helper function HandleMetaValueCheck to reduce code duplication and improve maintainability.

Also applies to: 1677-1677


1781-1793: Refactor duplicate error handling code.
[REFACTOR_SUGGESTion]

- if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) {
-   if (ExpectedStale(meta_value)) {
-     s = Status::NotFound();
-   } else {
-     return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast[int](DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(meta_value)));
-   }
- }
+ if (!HandleMetaValueCheck(s, meta_value, DataType::kZSets, key)) {
+   return s;
+ }

Same suggestion as above to extract the repeated pattern of checking meta_value and handling errors into a helper function HandleMetaValueCheck to reduce code duplication and improve maintainability.

Also applies to: 1793-1793


1815-1826: Refactor duplicate error handling code.
[REFACTOR_SUGGESTion]

- if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) {
-   if (ExpectedStale(meta_value)) {
-     s = Status::NotFound();
-   } else {
-     return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast[int](DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(meta_value)));
-   }
- }
+ if (!HandleMetaValueCheck(s, meta_value, DataType::kZSets, key)) {
+   return s;
+ }

Same suggestion as above to extract the repeated pattern of checking meta_value and handling errors into a helper function HandleMetaValueCheck to reduce code duplication and improve maintainability.

Also applies to: 1826-1826

Comment on lines 393 to 416
rocksdb::ReadOptions& read_options, std::string&& prefetch_meta) {
std::string value(std::move(prefetch_meta));
BaseMetaKey base_meta_key(key);
auto s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
Status s;
if (value.empty()) {
s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
}
Copy link

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Ensure robust handling of empty prefetch_meta in GetStreamMeta.

Similar to the earlier comment in XRange, the handling of an empty prefetch_meta in GetStreamMeta might lead to issues if not managed correctly. Consider adding explicit checks or handling strategies to manage cases where prefetch_meta might be empty or invalid.

+ if (value.empty()) {
+   return Status::InvalidArgument("Prefetch meta data cannot be empty.");
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rocksdb::ReadOptions& read_options, std::string&& prefetch_meta) {
std::string value(std::move(prefetch_meta));
BaseMetaKey base_meta_key(key);
auto s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
Status s;
if (value.empty()) {
s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
}
rocksdb::ReadOptions& read_options, std::string&& prefetch_meta) {
std::string value(std::move(prefetch_meta));
if (value.empty()) {
return Status::InvalidArgument("Prefetch meta data cannot be empty.");
}
BaseMetaKey base_meta_key(key);
Status s;
if (value.empty()) {
s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

这里的value为empty表明还没有执行过getmeta的操作,所以需要进行get。如果不是empty,表明已经执行过getmeta操作,而且类型一定是匹配的,此时只需要解析meta value即可。

Copy link

Choose a reason for hiding this comment

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

@wangshao1, thanks for clarifying the operational logic behind handling an empty prefetch_meta in the GetStreamMeta function. Your explanation about the necessity of performing a get operation when value is empty, and directly parsing the meta value when it's not, helps ensure the correct handling of metadata based on its state. I appreciate your insight and will note this for future reviews.


Learnings added
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_streams.cc:0-0
Timestamp: 2024-06-20T06:55:33.236Z
Learning: In the `GetStreamMeta` function of `redis_streams.cc`, an empty `prefetch_meta` indicates that the `getmeta` operation has not been performed, necessitating a database fetch. If `prefetch_meta` is not empty, it implies that the meta value has already been fetched and the type matches, allowing for direct parsing.

Note: Learnings are effective only in the context of specific code segments. To apply general coding guidelines, please configure review instructions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8d838fc and 38fdbaa.

Files selected for processing (2)
  • src/storage/src/redis_hashes.cc (6 hunks)
  • src/storage/src/redis_strings.cc (15 hunks)
Files skipped from review as they are similar to previous changes (2)
  • src/storage/src/redis_hashes.cc
  • src/storage/src/redis_strings.cc

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 38fdbaa and 3ee522f.

Files selected for processing (6)
  • src/storage/src/redis_hashes.cc (22 hunks)
  • src/storage/src/redis_lists.cc (22 hunks)
  • src/storage/src/redis_sets.cc (29 hunks)
  • src/storage/src/redis_streams.cc (4 hunks)
  • src/storage/src/redis_strings.cc (34 hunks)
  • src/storage/src/redis_zsets.cc (30 hunks)
Files skipped from review as they are similar to previous changes (5)
  • src/storage/src/redis_lists.cc
  • src/storage/src/redis_sets.cc
  • src/storage/src/redis_streams.cc
  • src/storage/src/redis_strings.cc
  • src/storage/src/redis_zsets.cc

Comment on lines 1108 to 1177
Status Redis::HashesExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);

BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
Status s;

if (meta_value.empty()) {
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Copy link

Choose a reason for hiding this comment

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

Ensure proper handling of meta_value being empty after attempting to fetch from the database.

  if (meta_value.empty()) {
    Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
+   if (!s.ok()) {
+     return s;  // Properly handle the case where the meta_value could not be fetched
+   }
    if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
      if (ExpectedStale(meta_value)) {
        s = Status::NotFound();
      } else {
        return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Status Redis::HashesExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);
BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
Status s;
if (meta_value.empty()) {
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
if (meta_value.empty()) {
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (!s.ok()) {
return s; // Properly handle the case where the meta_value could not be fetched
}
if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static

Comment on lines 1175 to 1254
Status Redis::HashesExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);

BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
Status s;
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Copy link

Choose a reason for hiding this comment

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

Check for potential unhandled cases where meta_value remains empty after fetching.

  if (meta_value.empty()) {
    s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
+   if (!s.ok()) {
+     return s;  // Ensure that errors during fetching are handled
+   }
    if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
      if (ExpectedStale(meta_value)) {
        s = Status::NotFound();
      } else {
        return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
      }
    }
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Status Redis::HashesExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);
BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
Status s;
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (!s.ok()) {
return s; // Ensure that errors during fetching are handled
}
if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
}
}

Comment on lines 1244 to 1332
Status Redis::HashesTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
Status s;
BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Copy link

Choose a reason for hiding this comment

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

Ensure error handling is robust when meta_value is not set after a fetch.

  if (meta_value.empty()) {
    s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
+   if (!s.ok()) {
+     return s;  // Ensure robust handling of cases where meta_value remains unset
+   }
    if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
      if (ExpectedStale(meta_value)) {
        s = Status::NotFound();
      } else {
        return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int](DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int](GetMetaValueType(meta_value))]);
      }
    }
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Status Redis::HashesTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
Status s;
BaseMetaKey base_meta_key(key);
Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Status Redis::HashesTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
Status s;
BaseMetaKey base_meta_key(key);
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (!s.ok()) {
return s; // Ensure robust handling of cases where meta_value remains unset
}
if (!ExpectedMetaValue(DataType::kHashes, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kHashes)] + ", get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
}
}

@AlexStocks AlexStocks changed the title fix: fix duplicate meta key read fix: duplicate meta key read Jun 20, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 25

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3ee522f and 07909b2.

Files selected for processing (7)
  • src/storage/src/redis_hashes.cc (22 hunks)
  • src/storage/src/redis_lists.cc (24 hunks)
  • src/storage/src/redis_sets.cc (29 hunks)
  • src/storage/src/redis_streams.cc (4 hunks)
  • src/storage/src/redis_strings.cc (35 hunks)
  • src/storage/src/redis_zsets.cc (30 hunks)
  • src/storage/src/storage.cc (1 hunks)
Files skipped from review as they are similar to previous changes (5)
  • src/storage/src/redis_hashes.cc
  • src/storage/src/redis_sets.cc
  • src/storage/src/redis_streams.cc
  • src/storage/src/redis_zsets.cc
  • src/storage/src/storage.cc
Additional context used
Learnings (1)
src/storage/src/redis_lists.cc (1)
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_streams.cc:0-0
Timestamp: 2024-06-20T06:55:33.400Z
Learning: In the `GetStreamMeta` function of `redis_streams.cc`, an empty `prefetch_meta` indicates that the `getmeta` operation has not been performed, necessitating a database fetch. If `prefetch_meta` is not empty, it implies that the meta value has already been fetched and the type matches, allowing for direct parsing.
Additional comments not posted (2)
src/storage/src/redis_lists.cc (2)

220-238: The implementation of LLen now uses a prefetch_meta parameter to potentially skip a metadata fetch. This is a good use of the parameter to optimize performance. However, ensure that the function's callers are updated to pass this new parameter.


1100-1118: The modifications to incorporate prefetch_meta in expiration, deletion, and TTL handling functions are consistent with the PR's goal to optimize metadata handling. Ensure that these changes are well-documented and tested to avoid regressions.

Also applies to: 1140-1158, 1177-1195, 1216-1234, 1256-1273

Verification successful

The repeated error suggests that the command structure or search pattern might be fundamentally flawed. To accurately verify if all related functions are updated to handle the new prefetch_meta parameter, we should try a different approach to gather the necessary information.


The search results confirm that the functions ListsExpire, ListsDel, ListsExpireat, ListsPersist, and ListsTTL have been updated to include the new prefetch_meta parameter in both their declarations and definitions.

  • src/storage/src/redis_strings.cc shows calls to these functions with the new parameter.
  • src/storage/src/redis.h and src/storage/src/redis_lists.cc show the updated function signatures.

This aligns with the review comment's goal to optimize metadata handling by incorporating prefetch_meta.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that all related functions are updated to handle the new `prefetch_meta` parameter.
# Test: Search for function calls without the new parameter. Expect: No occurrences.

rg --type cpp "ListsExpire\(|ListsDel\(|ListsExpireat\(|ListsPersist\(|ListsTTL\(" --files-without-match "std::string&& prefetch_meta"

Length of output: 204



Script:

#!/bin/bash
# Description: Verify that all related functions are updated to handle the new `prefetch_meta` parameter.
# Test: Search for function definitions without the new parameter. Expect: No occurrences.

rg --type cpp "ListsExpire\(|ListsDel\(|ListsExpireat\(|ListsPersist\(|ListsTTL\(" --files-without-match "std::string&& prefetch_meta"

Length of output: 204



Script:

#!/bin/bash
# Description: Verify that all related functions are updated to handle the new `prefetch_meta` parameter.
# Test: Search for function definitions without the new parameter. Expect: No occurrences.

rg --type cpp "ListsExpire\(|ListsDel\(|ListsExpireat\(|ListsPersist\(|ListsTTL\(" --files-without-match "std::string&& prefetch_meta"

Length of output: 204



Script:

#!/bin/bash
# Description: Verify that all related functions are updated to handle the new `prefetch_meta` parameter.
# Test: Search for function definitions without the new parameter. Expect: No occurrences.

# Correcting the search pattern to ensure accurate results
rg --type cpp "ListsExpire\(|ListsDel\(|ListsExpireat\(|ListsPersist\(|ListsTTL\(" --files-without-match "std::string&& prefetch_meta"

Length of output: 204



Script:

#!/bin/bash
# Description: Verify that all related functions are updated to handle the new `prefetch_meta` parameter.
# Test: Search for the function definitions and ensure that they include the new parameter.

# Search for the function definitions of interest and print their signatures
rg --type cpp "^(.*ListsExpire|.*ListsDel|.*ListsExpireat|.*ListsPersist|.*ListsTTL)\s*\(" -g '*.cc' -g '*.h'

Length of output: 1732

Comment on lines +1403 to +1420
Status Redis::StringsPersist(const Slice& key, std::string&& prefetch_meta) {
std::string value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);

BaseKey base_key(key);
Status s = db_->Get(default_read_options_, base_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
Status s;

// value is empty means no meta value get before,
// we should get meta first
if (value.empty()) {
s = db_->Get(default_read_options_, base_key.Encode(), &value);
if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) {
if (ExpectedStale(value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument(
"WRONGTYPE, key: " + key.ToString() + ", expect type: " +
DataTypeStrings[static_cast<int>(DataType::kStrings)] + ", get type: " +
DataTypeStrings[static_cast<int>(GetMetaValueType(value))]);
Copy link

Choose a reason for hiding this comment

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

Centralize error message creation to enhance code cleanliness.

Repeated logic for generating type error messages suggests the need for a centralized method. This would make the code cleaner and easier to maintain.

- "WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast[int](DataType::kStrings)] + ", get type: " + DataTypeStrings[static_cast[int](GetMetaValueType(value))]
+ return handleTypeError(key.ToString(), value);

Committable suggestion was skipped due to low confidence.

}
// when reaches here, either s is not found or s is ok but expired
Copy link
Collaborator

Choose a reason for hiding this comment

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

相当简洁,cool

return s;
}
if (s.ok() && !ExpectedStale(old_value)) {
return s;
Copy link
Collaborator

Choose a reason for hiding this comment

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

这里返回了个 ok 回去, 需要让 *ret = 0吗?

@wangshao1 wangshao1 force-pushed the bugfix/fix_repeat_get_meta branch from 9d1f589 to 017088a Compare June 21, 2024 06:49
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 07909b2 and 017088a.

Files selected for processing (8)
  • src/storage/src/redis.h (7 hunks)
  • src/storage/src/redis_hashes.cc (22 hunks)
  • src/storage/src/redis_lists.cc (24 hunks)
  • src/storage/src/redis_sets.cc (29 hunks)
  • src/storage/src/redis_streams.cc (4 hunks)
  • src/storage/src/redis_strings.cc (35 hunks)
  • src/storage/src/redis_zsets.cc (30 hunks)
  • src/storage/src/storage.cc (1 hunks)
Files skipped from review as they are similar to previous changes (5)
  • src/storage/src/redis.h
  • src/storage/src/redis_hashes.cc
  • src/storage/src/redis_streams.cc
  • src/storage/src/redis_zsets.cc
  • src/storage/src/storage.cc
Additional context used
Learnings (3)
src/storage/src/redis_lists.cc (1)
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_streams.cc:0-0
Timestamp: 2024-06-20T06:55:33.400Z
Learning: In the `GetStreamMeta` function of `redis_streams.cc`, an empty `prefetch_meta` indicates that the `getmeta` operation has not been performed, necessitating a database fetch. If `prefetch_meta` is not empty, it implies that the meta value has already been fetched and the type matches, allowing for direct parsing.
src/storage/src/redis_strings.cc (2)
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_strings.cc:0-0
Timestamp: 2024-06-20T09:21:39.323Z
Learning: Refactor involving extensive code changes should be deferred to subsequent versions to avoid risks before major releases. This is tracked under issue #2751 for the Pika project.
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_sets.cc:0-0
Timestamp: 2024-06-20T09:25:58.037Z
Learning: Refactor involving extensive code changes should be deferred to subsequent versions to avoid risks before major releases. This is tracked under issue #2751 for the Pika project.
src/storage/src/redis_sets.cc (2)
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis.h:249-249
Timestamp: 2024-06-20T09:24:32.373Z
Learning: In certain parts of the codebase, the `SCard` function is called with an empty string for the `std::string&& prefetch_meta` parameter because there is no pre-fetched metadata. In these cases, the function is designed to fetch the metadata from the database if the `prefetch_meta` is empty.
User: wangshao1
PR: OpenAtomFoundation/pika#2744
File: src/storage/src/redis_sets.cc:0-0
Timestamp: 2024-06-20T09:25:58.037Z
Learning: Refactor involving extensive code changes should be deferred to subsequent versions to avoid risks before major releases. This is tracked under issue #2751 for the Pika project.
Additional comments not posted (23)
src/storage/src/redis_lists.cc (18)

270-270: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 271-271, 272-272, 273-273


328-328: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 329-329, 330-330, 331-331


384-384: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 385-385, 386-386, 387-387


428-428: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 429-429, 430-430, 431-431


488-488: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 489-489, 490-490, 491-491


558-558: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 559-559, 560-560, 561-561


690-690: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 691-691, 692-692, 693-693


734-734: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 735-735, 736-736, 737-737


807-807: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 808-808, 809-809, 810-810


864-864: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 865-865, 866-866, 867-867


957-957: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 958-958, 959-959, 960-960


1014-1014: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1015-1015, 1016-1016, 1017-1017


1070-1070: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1071-1071, 1072-1072, 1073-1073


1100-1100: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1101-1101, 1104-1104, 1105-1105, 1106-1106, 1107-1107, 1108-1108, 1109-1109, 1110-1110, 1111-1111, 1112-1112, 1113-1113, 1114-1114, 1115-1115, 1116-1116, 1117-1117, 1118-1118


1140-1140: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1141-1141, 1144-1144, 1145-1145, 1146-1146, 1147-1147, 1148-1148, 1149-1149, 1150-1150, 1151-1151, 1152-1152, 1153-1153, 1154-1154, 1155-1155, 1156-1156, 1157-1157, 1158-1158


1177-1177: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1178-1178, 1181-1181, 1182-1182, 1183-1183, 1184-1184, 1185-1185, 1186-1186, 1187-1187, 1188-1188, 1189-1189, 1190-1190, 1191-1191, 1192-1192, 1193-1193, 1194-1194, 1195-1195


1216-1216: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1217-1217, 1220-1220, 1221-1221, 1222-1222, 1223-1223, 1224-1224, 1225-1225, 1226-1226, 1227-1227, 1228-1228, 1229-1229, 1230-1230, 1231-1231, 1232-1232, 1233-1233, 1234-1234


1256-1256: Skip: Duplicate comment.

This comment regarding error handling for incorrect data types was previously addressed in lines 220-238.

Also applies to: 1257-1257, 1259-1259, 1260-1260, 1261-1261, 1262-1262, 1263-1263, 1264-1264, 1265-1265, 1266-1266, 1267-1267, 1268-1268, 1269-1269, 1270-1270, 1271-1271, 1272-1272, 1273-1273

src/storage/src/redis_strings.cc (5)

1299-1316: Add prefetch_meta parameter to StringsExpire function

The StringsExpire function has been updated to include a std::string&& prefetch_meta parameter. This change allows for more efficient metadata handling by potentially reducing the need for a metadata fetch if it's already prefetched. Ensure that all calls to this function are updated to pass the new parameter where necessary.


1335-1352: Add prefetch_meta parameter to StringsDel function

The StringsDel function now accepts a std::string&& prefetch_meta parameter, which is intended to optimize metadata handling by using prefetched metadata. This update aligns with the changes made across other string-related functions, maintaining consistency in the API. Ensure that calls to StringsDel are updated accordingly.


1366-1383: Add prefetch_meta parameter to StringsExpireat function

The function StringsExpireat has been modified to include a std::string&& prefetch_meta parameter. This change is part of a broader effort to optimize metadata handling across the Redis implementation. It's important to ensure that all function calls are updated to accommodate this new parameter.


1403-1420: Add prefetch_meta parameter to StringsPersist function

The StringsPersist function has been updated to include a std::string&& prefetch_meta parameter. This parameter is used to optimize the handling of metadata, potentially reducing the need for additional metadata fetches. This change should be reflected in all calls to this function to ensure consistency.


1441-1458: Add prefetch_meta parameter to StringsTTL function

The StringsTTL function now includes a std::string&& prefetch_meta parameter. This addition is intended to optimize metadata handling by leveraging prefetched metadata, which can improve performance. Ensure that all relevant function calls are updated to pass this new parameter.

Comment on lines +207 to +210
return Status::InvalidArgument(
"WRONGTYPE, key: " + keys[idx] + ", expect type: " +
DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
Copy link

Choose a reason for hiding this comment

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

Consistent issue with error handling across set operations.

The error handling for type mismatches is consistent across various functions but could benefit significantly from a centralized approach or utility function as suggested above. This would ensure that any changes to the error format or logic only need to be made in one place, improving the code's maintainability.

Also applies to: 229-232, 298-301, 321-324, 370-373, 428-431, 454-457, 529-532, 559-562, 614-617, 666-669, 706-709, 716-719, 760-763, 822-825, 868-871, 932-935, 1049-1052, 1123-1126, 1190-1193, 1250-1253, 1292-1295, 1352-1355

Comment on lines +1410 to +1428
rocksdb::Status Redis::SetsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) {
std::string meta_value(std::move(prefetch_meta));
ScopeRecordLock l(lock_mgr_, key);

BaseMetaKey base_meta_key(key);
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
rocksdb::Status s;

// meta_value is empty means no meta value get before,
// we should get meta first
if (meta_value.empty()) {
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument(
"WRONGTYPE, key: " + key.ToString() + ", expect type: " +
DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Copy link

Choose a reason for hiding this comment

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

Refactor suggestion for error handling and metadata fetching in expiration and deletion methods.

The pattern of fetching metadata and handling errors is repeated in multiple functions (SetsExpire, SetsDel, SetsExpireat, SetsPersist, SetsTTL). Consider abstracting these common operations into helper functions to reduce code duplication and improve clarity.

+ rocksdb::Status fetchAndValidateMeta(const Slice& key, std::string& meta_value) {
+   BaseMetaKey base_meta_key(key);
+   rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
+   if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
+     if (ExpectedStale(meta_value)) {
+       return Status::NotFound();
+     } else {
+       return generateTypeError(key, DataType::kSets, GetMetaValueType(meta_value));
+     }
+   }
+   return s;
+ }

- if (meta_value.empty()) {
-   s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
-   if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
-     if (ExpectedStale(meta_value)) {
-       s = Status::NotFound();
-     } else {
-       return Status::InvalidArgument(
-       "WRONGTYPE, key: " + key.ToString() + ", expect type: " +
-       DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
-       DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
-     }
-   }
- }
+ if (meta_value.empty()) {
+   s = fetchAndValidateMeta(key, meta_value);
+   if (!s.ok()) return s;
+ }

Also applies to: 1450-1468, 1487-1505, 1526-1544, 1566-1583

Comment on lines +152 to +167
rocksdb::Status Redis::SCard(const Slice& key, int32_t* ret, std::string&& meta) {
*ret = 0;
std::string meta_value;

BaseMetaKey base_meta_key(key);
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
std::string meta_value(std::move(meta));
rocksdb::Status s;
if (meta_value.empty()) {
BaseMetaKey base_meta_key(key);
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument(
"WRONGTYPE, key: " + key.ToString() + ", expect type: " +
DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
Copy link

Choose a reason for hiding this comment

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

Potential issue with handling of metadata prefetch parameter in SCard.

The function now accepts a std::string&& meta parameter for metadata prefetching. However, there's a logical inconsistency:

  • If meta_value is empty, the code fetches metadata from the database. This behavior should be explicitly documented or handled more gracefully to avoid confusion.
  • The error message for type mismatch (WRONGTYPE) is repeated multiple times across various functions. Consider refactoring to a helper function to reduce redundancy and improve maintainability.
- "WRONGTYPE, key: " + key.ToString() + ", expect type: " +
- DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
- DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
+ generateTypeError(key, DataType::kSets, GetMetaValueType(meta_value));

// Helper function
std::string generateTypeError(const Slice& key, DataType expected, DataType actual) {
  return fmt::format("WRONGTYPE, key: {}, expect type: {}, get type: {}",
                     key.ToString(),
                     DataTypeStrings[static_cast<int>(expected)],
                     DataTypeStrings[static_cast<int>(actual)]);
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rocksdb::Status Redis::SCard(const Slice& key, int32_t* ret, std::string&& meta) {
*ret = 0;
std::string meta_value;
BaseMetaKey base_meta_key(key);
rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast<int>(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
std::string meta_value(std::move(meta));
rocksdb::Status s;
if (meta_value.empty()) {
BaseMetaKey base_meta_key(key);
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument(
"WRONGTYPE, key: " + key.ToString() + ", expect type: " +
DataTypeStrings[static_cast<int>(DataType::kSets)] + ", get type: " +
DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
}
rocksdb::Status Redis::SCard(const Slice& key, int32_t* ret, std::string&& meta) {
*ret = 0;
std::string meta_value(std::move(meta));
rocksdb::Status s;
if (meta_value.empty()) {
BaseMetaKey base_meta_key(key);
s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value);
if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) {
if (ExpectedStale(meta_value)) {
s = Status::NotFound();
} else {
return Status::InvalidArgument(generateTypeError(key, DataType::kSets, GetMetaValueType(meta_value)));
}
}
}
// Rest of the function...
}
// Helper function
std::string generateTypeError(const Slice& key, DataType expected, DataType actual) {
return fmt::format("WRONGTYPE, key: {}, expect type: {}, get type: {}",
key.ToString(),
DataTypeStrings[static_cast<int>(expected)],
DataTypeStrings[static_cast<int>(actual)]);
}

@@ -211,17 +217,25 @@ Status Redis::LInsert(const Slice& key, const BeforeOrAfter& before_or_after, co
return s;
}

Status Redis::LLen(const Slice& key, uint64_t* len) {
Status Redis::LLen(const Slice& key, uint64_t* len, std::string&& prefetch_meta) {
Copy link

Choose a reason for hiding this comment

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

Refactor: Standardize error handling for data type mismatches.

The error handling for incorrect data type is repeated across various functions. Consider refactoring this into a helper function to reduce code duplication and improve maintainability.

- return Status::InvalidArgument(
-   "WRONGTYPE, key: " + key.ToString() + ", expect type: " +
-   DataTypeStrings[static_cast<int>(DataType::kLists)] + ", get type: " +
-   DataTypeStrings[static_cast<int>(GetMetaValueType(meta_value))]);
+ return HandleWrongType(DataType::kLists, meta_value, key);

Also applies to: 222-222, 224-224, 225-225, 226-226, 227-227, 228-228, 229-229, 230-230, 231-231, 232-232, 233-233, 234-234, 235-235, 236-236, 237-237, 238-238

@chejinge chejinge merged commit 8dea10f into OpenAtomFoundation:unstable Jun 21, 2024
13 checks passed
cheniujh pushed a commit to cheniujh/pika that referenced this pull request Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4.0.0 ☢️ Bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants