Skip to content

Commit

Permalink
Allow stale values requests to be repeated
Browse files Browse the repository at this point in the history
This addresses issue numberscope#154, using the same technique as PR numberscope#127.
  • Loading branch information
Aaron Fenyes committed Sep 24, 2024
1 parent 3162931 commit e89c654
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 13 deletions.
8 changes: 4 additions & 4 deletions flaskr/nscope/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ class Sequence(db.Model):
# Postgres reserved word, so we use a different name.
shift = db.Column(db.Integer, unique=False, nullable=False, default=0)
values = db.Column(db.ARRAY(db.String), unique=False, nullable=True)
values_requested = db.Column(db.Boolean, nullable=False, default=False)
raw_refs = db.Column(db.String, unique=False, nullable=True)
backrefs = db.Column(db.ARRAY(db.String), unique=False, nullable=True)
ref_count = db.Column(db.Integer, nullable=True, default=None)
# The start time of the last attempt to fetch metadata, in nanoseconds since
# the UNIX epoch. A PostgreSQL BigInteger is eight bytes, including sign, so
# this should work until the early 2260s
# The start times of the last attempt to fetch values and metadata, in
# nanoseconds since the UNIX epoch. A PostgreSQL BigInteger is eight bytes,
# including sign, so this should work until the early 2260s
values_req_time = db.Column(db.BigInteger, nullable=True, default=None)
meta_req_time = db.Column(db.BigInteger, nullable=True, default=None)
# Sadly, multidimensional arrays can't vary in dimension
# so we store factorization arrays as strings
Expand Down
53 changes: 44 additions & 9 deletions flaskr/nscope/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,16 +235,38 @@ def fetch_values(oeis_id):
OEIS (if it has not already been), and returns a Sequence object
with the values filled in.
"""
# First check if it is in the database
seq = find_oeis_sequence(oeis_id)
# See if we already have the values:
if seq.values is not None: return seq
# See if getting them is in progress:
if seq.values_requested:
return LookupError("Value fetching for {oeis_id} in progress.")
seq.values_requested = True
if seq.values is not None:
# We already have the values in the database, so we just return them
return seq

our_req_time = time.time_ns()
last_req_time = seq.values_req_time
if last_req_time is not None:
# we chose `max_wait = 3` pretty haphazardly. it matches the minimum
# `max_wait` for a metadata request that has some refs downloaded
# already, and it's longer than the time it took to download the A000521
# b-file on Glen's connection (two seconds for 4 MB)
waited = (our_req_time - last_req_time) / 1e9
max_wait = 3
if waited < max_wait:
return LookupError(
f"Values for {oeis_id} were already requested {waited:.1f} "
"seconds ago. A new request can be made if the old one takes "
f"longer than {max_wait:.1f} seconds."
)

#---------------------------------------------------------------------------
# if we've gotten this far, we don't have the values in the database yet,
# and we don't think any other thread is likely to come back with them
#---------------------------------------------------------------------------

# Record the time we set out to fetch the values, so later threads can
# judge how likely we are to ever come back
seq.values_req_time = our_req_time
db.session.commit()
# Now try to get it from the OEIS:

# Try to get the b-file from the OEIS:
b_text = oeis_get(f'/{oeis_id}/b{oeis_id[1:]}.txt', json=False)
# Test for 404 error. Hat tip StackOverflow user Lukasa
# https://stackoverflow.com/a/19343099
Expand Down Expand Up @@ -283,7 +305,20 @@ def fetch_values(oeis_id):
if not seq.name:
seq.name = name or placeholder_name(oeis_id)
seq.shift = first
db.session.commit()

# We write what we've found to the database in the following situations:
#
# - No more recent thread has set out to fetch the same metadata
#
# - A more recent thread has set out to fetch the same metadata, but we got
# back before any other thread did
#
# This is equivalent to the condition in the `if` statement below because
# the only way for `seq.values_req_time == our_req_time` to be false is for
# a more recent thread to have overwritten the request time
if seq.values_req_time == our_req_time or seq.values is None:
db.session.commit()

return seq

def fetch_factors(oeis_id, num_elements = -1, timeout = 10):
Expand Down

0 comments on commit e89c654

Please sign in to comment.