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

Store creator hash prefixes in a separate lookup file #27731

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

zenparsing
Copy link
Collaborator

Resolves brave/brave-browser#43994

Submitter Checklist:

  • I confirm that no security/privacy review is needed and no other type of reviews are needed, or that I have requested them
  • There is a ticket for my issue
  • Used Github auto-closing keywords in the PR description above
  • Wrote a good PR/commit description
  • Squashed any review feedback or "fixup" commits before merge, so that history is a record of what happened in the repo, not your PR
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally:
    • npm run test -- brave_browser_tests, npm run test -- brave_unit_tests wiki
    • npm run presubmit wiki, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed)

Reviewer Checklist:

  • A security review is not needed, or a link to one is included in the PR description
  • New files have MPL-2.0 license header
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

@zenparsing zenparsing force-pushed the ksmith-prefix-list-v2 branch 6 times, most recently from 11de286 to a327bb5 Compare February 25, 2025 20:42
@zenparsing zenparsing force-pushed the ksmith-prefix-list-v2 branch 3 times, most recently from 9f6e4ff to f730894 Compare February 28, 2025 12:47
@zenparsing zenparsing marked this pull request as ready for review February 28, 2025 14:22
@zenparsing zenparsing requested review from a team as code owners February 28, 2025 14:22
@zenparsing zenparsing requested a review from atuchin-m February 28, 2025 14:23

// A random-access iterator over prefixes stored in an uncompressed prefix list,
// suitable for binary search.
class HashPrefixIterator {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm, do we really need this thing?
If it's only to support std::binary_search, we can just compare [0.. count-1] indexes + a custom compare function instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a rename (and cleanup) of an existing class currently used by PrefixListReader.

Copy link
Collaborator

Choose a reason for hiding this comment

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

O, thanks, I missed that part.
I see it uses to make sanity check that the first few prefixes are in order. That code can be moved to UpdatePrefixes.
If we can rid off it completely, it will be great.

if (!reader.ReadU32LittleEndian(parts.prefix_size)) {
return std::nullopt;
}
parts.prefixes = reader.remaining_span();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe we need to verify size here. Otherwise we can get an overflow in case the file is broken (i.e. with a sudden shutdown)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See IsValidFile for span-length validation.

static scoped_refptr<base::SequencedTaskRunner> CreateTaskRunner() {
return base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe SKIP_SHUTDOWN?
Also does it make sense to reuse one of the current task runner to simplify things?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated to use SKIP_ON_SHUTDOWN. I will look into the possibility of reusing a task runner.

HashPrefixStore& operator=(const HashPrefixStore&) = delete;

// Opens the hash prefix file, if not already open.
bool Open();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move internal methods to the private section.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This method is intentionally public. It's used by the unit tests for instance, but in principle could be used by a client to manually control opening/closing.

uint32 prefix_size;
};

interface HashPrefixStore {
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 use actually use this interface for IPC? If not why just not use sequenceBound?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I considered passing this interface to the Rewards engine, but decided to leave that for a future improvement. In the meantime, it is used to run the interface on a different thread (via RemoteWorker). However, if you aren't comfortable with that approach, I can use SequenceBound instead.

@zenparsing zenparsing force-pushed the ksmith-prefix-list-v2 branch from f730894 to a9d51f7 Compare February 28, 2025 15:18
Copy link
Contributor

[puLL-Merge] - brave/brave-core@27731

Description

This PR implements a new storage system for creator hash prefixes in Brave Rewards, moving them from a SQLite database table to a dedicated memory-mapped file. This change aims to improve performance and reduce memory usage by keeping the hash prefixes in a more efficient format that can be searched directly without database queries.

Changes

Changes

  1. HashPrefixStore Implementation:
  • Added new HashPrefixStore class for managing creator hash prefixes in a memory-mapped file
  • Implements file format versioning and validation
  • Provides methods for updating and searching prefixes
  1. Database Migration:
  • Added migration v41 to remove the old publisher_prefix_list table
  • Updated state migration to v15 to reset server publisher list timestamp
  • Updated database schema version
  1. Hash Prefix Iterator:
  • Replaced PrefixIterator with new HashPrefixIterator implementation
  • Maintains compatibility with STL algorithms while working with memory-mapped data
  1. Integration Changes:
  • Modified RewardsServiceImpl to use new HashPrefixStore
  • Updated Publisher class to use new prefix store methods
  • Added new Mojo interfaces for hash prefix operations
  1. iOS Support:
  • Added iOS-specific implementation of the new storage system
  • Updated BraveRewardsAPI to handle the new creator prefix store
sequenceDiagram
    participant Client
    participant RewardsServiceImpl
    participant HashPrefixStore
    participant MemoryMappedFile

    Client->>RewardsServiceImpl: UpdateCreatorPrefixStore(data)
    RewardsServiceImpl->>HashPrefixStore: UpdatePrefixes(prefixes, size)
    HashPrefixStore->>HashPrefixStore: Close()
    HashPrefixStore->>HashPrefixStore: WriteFileHeader()
    HashPrefixStore->>HashPrefixStore: WritePrefixes()
    HashPrefixStore-->>RewardsServiceImpl: success
    RewardsServiceImpl-->>Client: success

    Client->>RewardsServiceImpl: ContainsPrefix(value)
    RewardsServiceImpl->>HashPrefixStore: ContainsPrefix(value)
    HashPrefixStore->>MemoryMappedFile: Open()
    HashPrefixStore->>HashPrefixStore: BinarySearch()
    HashPrefixStore-->>RewardsServiceImpl: result
    RewardsServiceImpl-->>Client: result
Loading

Security Hotspots

  1. File Format Validation: The code validates file headers and content in ParseFile(), but carefully review the validation logic for potential edge cases or overflow conditions.

  2. Memory Mapping: The implementation uses memory-mapped files which could expose memory if not properly handled. Ensure proper error handling around file mapping operations.

Copy link
Contributor

@emerick emerick left a comment

Choose a reason for hiding this comment

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

++rewards

@@ -236,12 +237,14 @@ void DeferCallback(base::Location location, Callback callback, Args&&... args) {
// read comment about file pathes at src\base\files\file_path.h
#if BUILDFLAG(IS_WIN)
const base::FilePath::StringType kDiagnosticLogPath(L"Rewards.log");
const base::FilePath::StringType kCreatorPrefixStore(L"RewardsCreators.db");
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we keep these in alphabetical order?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

@zenparsing zenparsing force-pushed the ksmith-prefix-list-v2 branch from a9d51f7 to 0cb3a99 Compare February 28, 2025 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Rewards, Perf] Optimize publisher_info_db
3 participants