Add support for decimals to PatternEntry (#9577)

Summary:
Add support for doubles to ObjectLibrary::PatternEntry.  This support will allow patterns containing a non-integer number to be parsed correctly.

Added appropriate test cases to cover this new option.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9577

Reviewed By: pdillinger

Differential Revision: D34269763

Pulled By: mrambacher

fbshipit-source-id: b5ce16cbd3665c2974ec0f3412ef2b403ef8b155
This commit is contained in:
mrambacher 2022-02-16 11:11:55 -08:00 committed by Facebook GitHub Bot
parent 48f6c2a049
commit c42d0cf862
4 changed files with 113 additions and 16 deletions

View File

@ -64,7 +64,7 @@
* Remove deprecated overloads of API DB::GetApproximateSizes. * Remove deprecated overloads of API DB::GetApproximateSizes.
* Remove deprecated option DBOptions::new_table_reader_for_compaction_inputs. * Remove deprecated option DBOptions::new_table_reader_for_compaction_inputs.
* Add Transaction::SetReadTimestampForValidation() and Transaction::SetCommitTimestamp(). Default impl returns NotSupported(). * Add Transaction::SetReadTimestampForValidation() and Transaction::SetCommitTimestamp(). Default impl returns NotSupported().
* Add support for decimal patterns to ObjectLibrary::PatternEntry
### Behavior Changes ### Behavior Changes
* Disallow the combination of DBOptions.use_direct_io_for_flush_and_compaction == true and DBOptions.writable_file_max_buffer_size == 0. This combination can cause WritableFileWriter::Append() to loop forever, and it does not make much sense in direct IO. * Disallow the combination of DBOptions.use_direct_io_for_flush_and_compaction == true and DBOptions.writable_file_max_buffer_size == 0. This combination can cause WritableFileWriter::Append() to loop forever, and it does not make much sense in direct IO.
* `ReadOptions::total_order_seek` no longer affects `DB::Get()`. The original motivation for this interaction has been obsolete since RocksDB has been able to detect whether the current prefix extractor is compatible with that used to generate table files, probably RocksDB 5.14.0. * `ReadOptions::total_order_seek` no longer affects `DB::Get()`. The original motivation for this interaction has been obsolete since RocksDB has been able to detect whether the current prefix extractor is compatible with that used to generate table files, probably RocksDB 5.14.0.

View File

@ -75,7 +75,8 @@ class ObjectLibrary {
kMatchZeroOrMore, // [suffix].* kMatchZeroOrMore, // [suffix].*
kMatchAtLeastOne, // [suffix].+ kMatchAtLeastOne, // [suffix].+
kMatchExact, // [suffix] kMatchExact, // [suffix]
kMatchNumeric, // [suffix][0-9]+ kMatchInteger, // [suffix][0-9]+
kMatchDecimal, // [suffix][0-9]+[.][0-9]+
}; };
public: public:
@ -123,8 +124,9 @@ class ObjectLibrary {
// Adds a separator (exact match of separator with trailing numbers) to the // Adds a separator (exact match of separator with trailing numbers) to the
// entry // entry
PatternEntry& AddNumber(const std::string& separator) { PatternEntry& AddNumber(const std::string& separator, bool is_int = true) {
separators_.emplace_back(separator, kMatchNumeric); separators_.emplace_back(separator,
(is_int) ? kMatchInteger : kMatchDecimal);
slength_ += separator.size() + 1; slength_ += separator.size() + 1;
return *this; return *this;
} }

View File

@ -15,6 +15,39 @@
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
namespace {
bool MatchesInteger(const std::string &target, size_t start, size_t pos) {
// If it is numeric, everything up to the match must be a number
int digits = 0;
while (start < pos) {
if (!isdigit(target[start++])) {
return false;
} else {
digits++;
}
}
return (digits > 0);
}
bool MatchesDecimal(const std::string &target, size_t start, size_t pos) {
int digits = 0;
for (bool point = false; start < pos; start++) {
if (target[start] == '.') {
if (point) {
return false;
} else {
point = true;
}
} else if (!isdigit(target[start])) {
return false;
} else {
digits++;
}
}
return (digits > 0);
}
} // namespace
size_t ObjectLibrary::PatternEntry::MatchSeparatorAt( size_t ObjectLibrary::PatternEntry::MatchSeparatorAt(
size_t start, Quantifier mode, const std::string &target, size_t tlen, size_t start, Quantifier mode, const std::string &target, size_t tlen,
const std::string &separator) const { const std::string &separator) const {
@ -36,12 +69,13 @@ size_t ObjectLibrary::PatternEntry::MatchSeparatorAt(
} }
if (pos == std::string::npos) { if (pos == std::string::npos) {
return pos; return pos;
} else if (mode == kMatchNumeric) { } else if (mode == kMatchInteger) {
// If it is numeric, everything up to the match must be a number if (!MatchesInteger(target, start, pos)) {
while (start < pos) {
if (!isdigit(target[start++])) {
return std::string::npos; return std::string::npos;
} }
} else if (mode == kMatchDecimal) {
if (!MatchesDecimal(target, start, pos)) {
return std::string::npos;
} }
} }
return pos + slen; return pos + slen;
@ -84,12 +118,10 @@ bool ObjectLibrary::PatternEntry::MatchesTarget(const std::string &name,
return (start == tlen); return (start == tlen);
} else if (start > tlen || (start == tlen && mode != kMatchZeroOrMore)) { } else if (start > tlen || (start == tlen && mode != kMatchZeroOrMore)) {
return false; return false;
} else if (mode == kMatchNumeric) { } else if (mode == kMatchInteger) {
while (start < tlen) { return MatchesInteger(target, start, tlen);
if (!isdigit(target[start++])) { } else if (mode == kMatchDecimal) {
return false; return MatchesDecimal(target, start, tlen);
}
}
} }
} }
return true; return true;

View File

@ -599,6 +599,69 @@ TEST_F(PatternEntryTest, TestNumericEntry) {
ASSERT_FALSE(entry.Matches("A:B")); ASSERT_FALSE(entry.Matches("A:B"));
ASSERT_FALSE(entry.Matches("A:1B")); ASSERT_FALSE(entry.Matches("A:1B"));
ASSERT_FALSE(entry.Matches("A:B1")); ASSERT_FALSE(entry.Matches("A:B1"));
entry.AddSeparator(":", false);
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_TRUE(entry.Matches("A:1:"));
ASSERT_TRUE(entry.Matches("A:11:"));
ASSERT_FALSE(entry.Matches("A:1"));
ASSERT_FALSE(entry.Matches("A:B1:"));
ASSERT_FALSE(entry.Matches("A:1B:"));
ASSERT_FALSE(entry.Matches("A::"));
}
TEST_F(PatternEntryTest, TestDoubleEntry) {
ObjectLibrary::PatternEntry entry("A", false);
entry.AddNumber(":", false);
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA:1"));
ASSERT_FALSE(entry.Matches("AA:11"));
ASSERT_FALSE(entry.Matches("A:B"));
ASSERT_FALSE(entry.Matches("A:1B"));
ASSERT_FALSE(entry.Matches("A:B1"));
ASSERT_TRUE(entry.Matches("A:1"));
ASSERT_TRUE(entry.Matches("A:11"));
ASSERT_TRUE(entry.Matches("A:1.1"));
ASSERT_TRUE(entry.Matches("A:11.11"));
ASSERT_TRUE(entry.Matches("A:1."));
ASSERT_TRUE(entry.Matches("A:.1"));
ASSERT_TRUE(entry.Matches("A:0.1"));
ASSERT_TRUE(entry.Matches("A:1.0"));
ASSERT_TRUE(entry.Matches("A:1.0"));
ASSERT_FALSE(entry.Matches("A:1.0."));
ASSERT_FALSE(entry.Matches("A:1.0.2"));
ASSERT_FALSE(entry.Matches("A:.1.0"));
ASSERT_FALSE(entry.Matches("A:..10"));
ASSERT_FALSE(entry.Matches("A:10.."));
ASSERT_FALSE(entry.Matches("A:."));
entry.AddSeparator(":", false);
ASSERT_FALSE(entry.Matches("A:1"));
ASSERT_FALSE(entry.Matches("A:1.0"));
ASSERT_TRUE(entry.Matches("A:11:"));
ASSERT_TRUE(entry.Matches("A:1.1:"));
ASSERT_TRUE(entry.Matches("A:11.11:"));
ASSERT_TRUE(entry.Matches("A:1.:"));
ASSERT_TRUE(entry.Matches("A:.1:"));
ASSERT_TRUE(entry.Matches("A:0.1:"));
ASSERT_TRUE(entry.Matches("A:1.0:"));
ASSERT_TRUE(entry.Matches("A:1.0:"));
ASSERT_FALSE(entry.Matches("A:1.0.:"));
ASSERT_FALSE(entry.Matches("A:1.0.2:"));
ASSERT_FALSE(entry.Matches("A:.1.0:"));
ASSERT_FALSE(entry.Matches("A:..10:"));
ASSERT_FALSE(entry.Matches("A:10..:"));
ASSERT_FALSE(entry.Matches("A:.:"));
ASSERT_FALSE(entry.Matches("A::"));
} }
TEST_F(PatternEntryTest, TestIndividualIdEntry) { TEST_F(PatternEntryTest, TestIndividualIdEntry) {