-
Notifications
You must be signed in to change notification settings - Fork 78
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
Improved version of UniqueList: OrderedSet #76
Changes from 7 commits
b326e1e
649b59b
f3c1a9e
0bf8ee9
3e8dad9
ae53aed
c479e60
3773736
f28ff6d
71ba1a7
9260457
1df0c66
5cfdc28
6035c06
f2f7940
4beba5a
316d9c6
1e62574
cfe0310
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,84 @@ | ||
# You'd normally call this a set, but Redis already has another data type for that | ||
class Kredis::Types::UniqueList < Kredis::Types::List | ||
proxying :multi, :ltrim, :exists? | ||
class Kredis::Types::UniqueList < Kredis::Types::Proxying | ||
proxying :multi, :zrange, :zrem, :zadd, :zremrangebyrank, :exists?, :del | ||
|
||
attr_accessor :typed, :limit | ||
|
||
def prepend(elements) | ||
elements = Array(elements).uniq | ||
return if elements.empty? | ||
def elements | ||
auto_fallback(:elements) do | ||
strings_to_types(zrange(0, -1) || [], typed) | ||
end | ||
end | ||
alias to_a elements | ||
|
||
multi do | ||
remove elements | ||
super | ||
ltrim 0, (limit - 1) if limit | ||
def remove(*elements) | ||
auto_migrate do | ||
zrem(types_to_strings(elements, typed)) | ||
end | ||
end | ||
|
||
def append(elements) | ||
elements = Array(elements).uniq | ||
return if elements.empty? | ||
def prepend(elements) | ||
auto_migrate do | ||
insert(elements, prepending: true) | ||
end | ||
end | ||
|
||
multi do | ||
remove elements | ||
super | ||
ltrim -limit, -1 if limit | ||
def append(elements) | ||
auto_migrate do | ||
insert(elements) | ||
end | ||
end | ||
alias << append | ||
|
||
private | ||
def insert(elements, prepending: false) | ||
elements = Array(elements) | ||
return if elements.empty? | ||
|
||
elements_with_scores = types_to_strings(elements, typed).map do |element| | ||
[ current_nanoseconds(negative: prepending), element ] | ||
end | ||
|
||
multi do | ||
zadd(elements_with_scores) | ||
trim(from_beginning: prepending) | ||
end | ||
end | ||
|
||
def current_nanoseconds(negative:) | ||
"%10.9f" % (negative ? -Time.now.to_f : Time.now.to_f) | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
end | ||
|
||
def trim(from_beginning:) | ||
return unless limit&.positive? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are negative/zero limits supported? If not, would fail earlier, e.g. in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea! |
||
|
||
if from_beginning | ||
zremrangebyrank(limit, -1) | ||
else | ||
zremrangebyrank(0, -(limit + 1)) | ||
end | ||
end | ||
|
||
def auto_fallback(method) | ||
yield | ||
rescue Redis::CommandError | ||
legacy_list.send(method) | ||
end | ||
|
||
def auto_migrate | ||
yield | ||
rescue Redis::CommandError | ||
migrate_list_to_sorted_set | ||
retry | ||
end | ||
|
||
def migrate_list_to_sorted_set | ||
legacy_elements = legacy_list.elements | ||
legacy_list.del | ||
append(legacy_elements) | ||
end | ||
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be within an atomic MULTI…EXEC? |
||
|
||
def legacy_list | ||
Kredis.unique_list_legacy(key, typed: typed, limit: limit, config: config, after_change: after_change) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# You'd normally call this a set, but Redis already has another data type for that | ||
class Kredis::Types::UniqueListLegacy < Kredis::Types::List | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed the existing |
||
proxying :multi, :ltrim, :exists? | ||
|
||
attr_accessor :typed, :limit | ||
|
||
def prepend(elements) | ||
elements = Array(elements).uniq | ||
return if elements.empty? | ||
|
||
multi do | ||
remove elements | ||
super | ||
ltrim 0, (limit - 1) if limit | ||
end | ||
end | ||
|
||
def append(elements) | ||
elements = Array(elements).uniq | ||
return if elements.empty? | ||
|
||
multi do | ||
remove elements | ||
super | ||
ltrim -limit, -1 if limit | ||
end | ||
end | ||
alias << append | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider LT / GT options for ordering safety, avoiding problems with clock skew.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not possible due to Redis server compatibility target being version 4.