There's no need to do the work that OnlineFileRequest does on a separate thread from the DefaultFileSource thread, and having AsyncTasks proxy to other tasks across a thread boundary adds needless complexity.
The migration was upgrading the schema, but not the schema version. As a result, the (expensive) migration was running every time an OfflineDatabase was constructed with a v2 database.
Fixes#4501
This new code can be used for rendering on the Main thread
while it will also work for rendering on the Map thread
before we make the switch. Needed by #2909.
The tile limit guard (when used) stops a download from continuing
when the tile limit is reached. This wraps the guard in a method
and employs it in both places currently necessary to ensure the
guard has a chance to function. Tests have been updated to
ensure the fix works for a less trivial tile limit scenario.
The core of the change is ensuring that ensureResource doesn't release Zalgo: it should be consistently async, rather than async in the case that the resource doesn't exist in the database, but sync if it does.
This ensures that status is reported in a more consistent sequence, regardless of the database state.
If the server keeps sending replies considered from the client in the
past (there is no way to tell if the server or client clock is wrong),
the client will try to interpolate a valid expiration time based
on the delta of the expiration intervals sent by the server.
If the intervals are always the same, exponential backoff kicks in
until we get a different expiration time from what we already have.
When we receive an expired tile, we don't immediately retry
because in case the server keeps serving an expired tile, that
would cause an infinite retry cycle.
Now we add an exponential delay, similarly to what we do for
connection errors.
SQLite REPLACE is *not* UPSERT. If a conflict occurs, it first deletes the existing row, then inserts a new row. This means that AUTOINCREMENT primary keys change. This will break foreign keys to that value, which we use.
Instead we must try an UPDATE, and fall back to an INSERT if the UPDATE changes zero rows.
The run loop will be kept alive because it has an `AsyncTask`. We
also can simple stop the loop with `uv_stop()`.
The `RunLoop` is still gonna be the last object to be destroyed
because it is the first object to be created in the thread, so
by design it won't outlive `Timer`s and `AsyncTask`s.
This patch won't change the current behavior, will just make
the code simpler.
If we don't do this, we can activate a request twice.
The issue here is that we use memory address as the 'key'. So if
we destroy a request, another request might take the same memory
address, or the same 'key'.
The entry at 'pendingRequests' survives the 'cancel()' and is
ultimatelly removed at 'activatePendingRequest()'. This is fine
unless a request is created using the same 'key' before we call
'activatePendingRequest()'.
The check if the request was canceled at 'activatePendingRequest()'
will be no longer valid, activating the request. At the same time
the request will be activated again by the task scheduled at the
constructor of the 'OnlineFileRequestImpl' class.