Skip to content

Commit 3b63cfe

Browse files
committed
Refactor #clean_old_tokens to reduce computational complexity.
* Previous version featured an `Enumerable#min_by` loop _inside_ a `while` loop, resulting in `O(n^2)` complexity. * Instead, break things into two separate loops, and skip altogether if they aren't even necessary.
1 parent f151222 commit 3b63cfe

File tree

1 file changed

+11
-3
lines changed
  • app/models/devise_token_auth/concerns

1 file changed

+11
-3
lines changed

app/models/devise_token_auth/concerns/user.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,17 @@ def max_client_tokens_exceeded?
258258
end
259259

260260
def clean_old_tokens
261-
while tokens.present? && max_client_tokens_exceeded?
262-
oldest_client_id, _tk = tokens.min_by { |_cid, v| v[:expiry] || v["expiry"] }
263-
tokens.delete(oldest_client_id)
261+
if tokens.present? && max_client_tokens_exceeded?
262+
# Using Enumerable#sort_by on a Hash will typecast it into an associative
263+
# Array (i.e. an Array of key-value Array pairs). However, since Hashes
264+
# have an internal order in Ruby 1.9+, the resulting sorted associative
265+
# Array can be converted back into a Hash, while maintaining the sorted
266+
# order.
267+
self.tokens = tokens.sort_by { |_cid, v| v[:expiry] || v['expiry'] }.to_h
268+
269+
# Since the tokens are sorted by expiry, shift the oldest client token
270+
# off the Hash until it no longer exceeds the maximum number of clients
271+
tokens.shift while max_client_tokens_exceeded?
264272
end
265273
end
266274
end

0 commit comments

Comments
 (0)