Skip to content

Commit

Permalink
And we are in bizniz
Browse files Browse the repository at this point in the history
  • Loading branch information
julik committed Jan 3, 2024
1 parent 89277af commit d9ff3b7
Showing 1 changed file with 6 additions and 23 deletions.
29 changes: 6 additions & 23 deletions lib/pecorino/sqlite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,12 @@ class Sanitizer < Struct.new(:connection)
include ActiveRecord::Sanitization::ClassMethods
end

def fractional_seconds_since_last_touched
# SQLite is peculiar in that its datetime functions do not give fractrional seconds.
# The only way to get seconds with fractions is to use the '%f' format specifier
# with strftime(). Since we need subsecond-precision timestamps for Pecorino, we need
# to jump through some hoops to perform our calculations on fractional seconds. The hoops entail
# subtracting the whole seconds from the fractional seconds
t_last_touched = <<~SQL.strip
strftime('%s', t.last_touched_at) + (strftime('%f', t.last_touched_at) - floor(strftime('%f', t.last_touched_at)))
SQL

"(#{fractional_seconds_from_now} - #{t_last_touched})"
end

def fractional_seconds_from_now
<<~SQL.strip
strftime('%s') + (strftime('%f') - floor(strftime('%f')))
SQL
end

def state(conn:, key:, capa:, leak_rate:)
query_params = {
key: key.to_s,
capa: capa.to_f,
leak_rate: leak_rate.to_f
leak_rate: leak_rate.to_f,
now_s: Time.now.to_f # SQLite is in-process, so having a consistent time between servers is impossible
}
# The `level` of the bucket is what got stored at `last_touched_at` time, and we can
# extrapolate from it to see how many tokens have leaked out since `last_touched_at` -
Expand All @@ -38,7 +20,7 @@ def state(conn:, key:, capa:, leak_rate:)
MAX(
0.0, MIN(
:capa,
t.level - (#{fractional_seconds_since_last_touched} * :leak_rate)
t.level - ((:now_s - t.last_touched_at) * :leak_rate)
)
)
FROM
Expand All @@ -65,6 +47,7 @@ def add_tokens(conn:, key:, capa:, leak_rate:, n_tokens:)
capa: capa.to_f,
delete_after_s: may_be_deleted_after_seconds,
leak_rate: leak_rate.to_f,
now_s: Time.now.to_f,
fillup: n_tokens.to_f,
id: SecureRandom.uuid # SQLite3 does not autogenerate UUIDs
}
Expand All @@ -76,7 +59,7 @@ def add_tokens(conn:, key:, capa:, leak_rate:, n_tokens:)
(
:id,
:key,
strftime('%Y-%m-%d %H:%M:%f'), -- Precision loss must be avoided here as it is used for calculations
:now_s, -- Precision loss must be avoided here as it is used for calculations
DATETIME('now', '+:delete_after_s seconds'), -- Precision loss is acceptable here
MAX(0.0,
MIN(
Expand All @@ -91,7 +74,7 @@ def add_tokens(conn:, key:, capa:, leak_rate:, n_tokens:)
level = MAX(0.0,
MIN(
:capa,
t.level + :fillup - (#{fractional_seconds_since_last_touched} * :leak_rate)
t.level + :fillup - ((:now_s - t.last_touched_at) * :leak_rate)
)
)
RETURNING
Expand Down

0 comments on commit d9ff3b7

Please sign in to comment.