mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-16 16:28:50 +00:00
index-only scans for pubkey+kind
This commit is contained in:
1
TODO
1
TODO
@ -15,7 +15,6 @@ features
|
|||||||
less verbose default logging
|
less verbose default logging
|
||||||
nice new config "units" feature, ie 1d instead of 86400
|
nice new config "units" feature, ie 1d instead of 86400
|
||||||
make it easier for a thread to setup a quadrable env
|
make it easier for a thread to setup a quadrable env
|
||||||
opt: PubkeyKind scans could be done index-only
|
|
||||||
|
|
||||||
rate limits
|
rate limits
|
||||||
slow-reader detection and back-pressure
|
slow-reader detection and back-pressure
|
||||||
|
39
src/DBScan.h
39
src/DBScan.h
@ -49,10 +49,16 @@ struct DBScan {
|
|||||||
std::string resumeKey;
|
std::string resumeKey;
|
||||||
uint64_t resumeVal;
|
uint64_t resumeVal;
|
||||||
|
|
||||||
|
enum class KeyMatchResult {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
NoButContinue,
|
||||||
|
};
|
||||||
|
|
||||||
std::function<bool()> isComplete;
|
std::function<bool()> isComplete;
|
||||||
std::function<void()> nextFilterItem;
|
std::function<void()> nextFilterItem;
|
||||||
std::function<void()> resetResume;
|
std::function<void()> resetResume;
|
||||||
std::function<bool(std::string_view, bool&)> keyMatch;
|
std::function<KeyMatchResult(std::string_view, bool&)> keyMatch;
|
||||||
|
|
||||||
DBScan(const NostrFilter &f_) : f(f_) {
|
DBScan(const NostrFilter &f_) : f(f_) {
|
||||||
remainingLimit = f.limit;
|
remainingLimit = f.limit;
|
||||||
@ -74,7 +80,7 @@ struct DBScan {
|
|||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool&){
|
keyMatch = [&, state](std::string_view k, bool&){
|
||||||
return k.starts_with(state->prefix);
|
return k.starts_with(state->prefix) ? KeyMatchResult::Yes : KeyMatchResult::No;
|
||||||
};
|
};
|
||||||
} else if (f.authors && f.kinds) {
|
} else if (f.authors && f.kinds) {
|
||||||
scanState = PubkeyKindScan{};
|
scanState = PubkeyKindScan{};
|
||||||
@ -98,16 +104,22 @@ struct DBScan {
|
|||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool &skipBack){
|
keyMatch = [&, state](std::string_view k, bool &skipBack){
|
||||||
if (!k.starts_with(state->prefix)) return false;
|
if (!k.starts_with(state->prefix)) return KeyMatchResult::No;
|
||||||
if (state->prefix.size() == 32 + 8) return true;
|
if (state->prefix.size() == 32 + 8) return KeyMatchResult::Yes;
|
||||||
|
|
||||||
ParsedKey_StringUint64Uint64 parsedKey(k);
|
ParsedKey_StringUint64Uint64 parsedKey(k);
|
||||||
if (parsedKey.n1 <= f.kinds->at(state->indexKind)) return true;
|
if (parsedKey.n1 == f.kinds->at(state->indexKind)) {
|
||||||
|
return KeyMatchResult::Yes;
|
||||||
|
} else if (parsedKey.n1 < f.kinds->at(state->indexKind)) {
|
||||||
|
// With a prefix pubkey, continue scanning (pubkey,kind) backwards because with this index
|
||||||
|
// we don't know the next pubkey to jump back to
|
||||||
|
return KeyMatchResult::NoButContinue;
|
||||||
|
}
|
||||||
|
|
||||||
resumeKey = makeKey_StringUint64Uint64(parsedKey.s, f.kinds->at(state->indexKind), MAX_U64);
|
resumeKey = makeKey_StringUint64Uint64(parsedKey.s, f.kinds->at(state->indexKind), MAX_U64);
|
||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
skipBack = true;
|
skipBack = true;
|
||||||
return false;
|
return KeyMatchResult::No;
|
||||||
};
|
};
|
||||||
} else if (f.authors) {
|
} else if (f.authors) {
|
||||||
scanState = PubkeyScan{};
|
scanState = PubkeyScan{};
|
||||||
@ -126,7 +138,7 @@ struct DBScan {
|
|||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool&){
|
keyMatch = [&, state](std::string_view k, bool&){
|
||||||
return k.starts_with(state->prefix);
|
return k.starts_with(state->prefix) ? KeyMatchResult::Yes : KeyMatchResult::No;
|
||||||
};
|
};
|
||||||
} else if (f.tags.size()) {
|
} else if (f.tags.size()) {
|
||||||
scanState = TagScan{f.tags.begin()};
|
scanState = TagScan{f.tags.begin()};
|
||||||
@ -150,7 +162,7 @@ struct DBScan {
|
|||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool&){
|
keyMatch = [&, state](std::string_view k, bool&){
|
||||||
return k.substr(0, state->search.size()) == state->search;
|
return k.substr(0, state->search.size()) == state->search ? KeyMatchResult::Yes : KeyMatchResult::No;
|
||||||
};
|
};
|
||||||
} else if (f.kinds) {
|
} else if (f.kinds) {
|
||||||
scanState = KindScan{};
|
scanState = KindScan{};
|
||||||
@ -170,7 +182,7 @@ struct DBScan {
|
|||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool&){
|
keyMatch = [&, state](std::string_view k, bool&){
|
||||||
ParsedKey_Uint64Uint64 parsedKey(k);
|
ParsedKey_Uint64Uint64 parsedKey(k);
|
||||||
return parsedKey.n1 == state->kind;
|
return parsedKey.n1 == state->kind ? KeyMatchResult::Yes : KeyMatchResult::No;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
scanState = CreatedAtScan{};
|
scanState = CreatedAtScan{};
|
||||||
@ -188,7 +200,7 @@ struct DBScan {
|
|||||||
resumeVal = MAX_U64;
|
resumeVal = MAX_U64;
|
||||||
};
|
};
|
||||||
keyMatch = [&, state](std::string_view k, bool&){
|
keyMatch = [&, state](std::string_view k, bool&){
|
||||||
return true;
|
return KeyMatchResult::Yes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +220,8 @@ struct DBScan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!keyMatch(k, skipBack)) return false;
|
auto matched = keyMatch(k, skipBack);
|
||||||
|
if (matched == KeyMatchResult::No) return false;
|
||||||
|
|
||||||
uint64_t created;
|
uint64_t created;
|
||||||
|
|
||||||
@ -234,7 +247,9 @@ struct DBScan {
|
|||||||
bool sent = false;
|
bool sent = false;
|
||||||
uint64_t levId = lmdb::from_sv<uint64_t>(v);
|
uint64_t levId = lmdb::from_sv<uint64_t>(v);
|
||||||
|
|
||||||
if (f.indexOnlyScans) {
|
if (matched == KeyMatchResult::NoButContinue) {
|
||||||
|
// Don't attempt to match filter
|
||||||
|
} else if (f.indexOnlyScans) {
|
||||||
if (f.doesMatchTimes(created)) {
|
if (f.doesMatchTimes(created)) {
|
||||||
handleEvent(levId);
|
handleEvent(levId);
|
||||||
sent = true;
|
sent = true;
|
||||||
|
@ -168,8 +168,7 @@ struct NostrFilter {
|
|||||||
|
|
||||||
if (limit > maxFilterLimit) limit = maxFilterLimit;
|
if (limit > maxFilterLimit) limit = maxFilterLimit;
|
||||||
|
|
||||||
indexOnlyScans = numMajorFields <= 1;
|
indexOnlyScans = (numMajorFields <= 1) || (numMajorFields == 2 && authors && kinds);
|
||||||
// FIXME: pubkeyKind scan could be serviced index-only too
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doesMatchTimes(uint64_t created) const {
|
bool doesMatchTimes(uint64_t created) const {
|
||||||
|
Reference in New Issue
Block a user