Merge pull request #71 from vector-im/bwindels/splitup-session-values

Store session values as separate entries in store
This commit is contained in:
Bruno Windels 2020-08-27 12:40:19 +00:00 committed by GitHub
commit a53c061f27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 37 deletions

View file

@ -24,7 +24,7 @@ export class Session {
constructor({storage, hsApi, sessionInfo}) { constructor({storage, hsApi, sessionInfo}) {
this._storage = storage; this._storage = storage;
this._hsApi = hsApi; this._hsApi = hsApi;
this._session = null; this._syncInfo = null;
this._sessionInfo = sessionInfo; this._sessionInfo = sessionInfo;
this._rooms = new ObservableMap(); this._rooms = new ObservableMap();
this._sendScheduler = new SendScheduler({hsApi, backoff: new RateLimitingBackoff()}); this._sendScheduler = new SendScheduler({hsApi, backoff: new RateLimitingBackoff()});
@ -42,11 +42,7 @@ export class Session {
this._storage.storeNames.pendingEvents, this._storage.storeNames.pendingEvents,
]); ]);
// restore session object // restore session object
this._session = await txn.session.get(); this._syncInfo = await txn.session.get("sync");
if (!this._session) {
this._session = {};
return;
}
const pendingEventsByRoomId = await this._getPendingEventsByRoom(txn); const pendingEventsByRoomId = await this._getPendingEventsByRoom(txn);
// load rooms // load rooms
const rooms = await txn.roomSummary.getAll(); const rooms = await txn.roomSummary.getAll();
@ -70,11 +66,9 @@ export class Session {
const txn = await this._storage.readWriteTxn([ const txn = await this._storage.readWriteTxn([
this._storage.storeNames.session this._storage.storeNames.session
]); ]);
const newSessionData = Object.assign({}, this._session, {serverVersions: lastVersionResponse}); txn.session.set("serverVersions", lastVersionResponse);
txn.session.set(newSessionData);
// TODO: what can we do if this throws? // TODO: what can we do if this throws?
await txn.complete(); await txn.complete();
this._session = newSessionData;
} }
this._sendScheduler.start(); this._sendScheduler.start();
@ -115,27 +109,27 @@ export class Session {
} }
writeSync(syncToken, syncFilterId, accountData, txn) { writeSync(syncToken, syncFilterId, accountData, txn) {
if (syncToken !== this._session.syncToken) { if (syncToken !== this.syncToken) {
// don't modify this._session because transaction might still fail const syncInfo = {token: syncToken, filterId: syncFilterId};
const newSessionData = Object.assign({}, this._session, {syncToken, syncFilterId}); // don't modify `this` because transaction might still fail
txn.session.set(newSessionData); txn.session.set("sync", syncInfo);
return newSessionData; return syncInfo;
} }
} }
afterSync(newSessionData) { afterSync(syncInfo) {
if (newSessionData) { if (syncInfo) {
// sync transaction succeeded, modify object state now // sync transaction succeeded, modify object state now
this._session = newSessionData; this._syncInfo = syncInfo;
} }
} }
get syncToken() { get syncToken() {
return this._session.syncToken; return this._syncInfo?.token;
} }
get syncFilterId() { get syncFilterId() {
return this._session.syncFilterId; return this._syncInfo?.filterId;
} }
get user() { get user() {
@ -149,8 +143,8 @@ export function tests() {
readTxn() { readTxn() {
return Promise.resolve({ return Promise.resolve({
session: { session: {
get() { get(key) {
return Promise.resolve(Object.assign({}, session)); return Promise.resolve(session[key]);
} }
}, },
pendingEvents: { pendingEvents: {
@ -172,22 +166,23 @@ export function tests() {
return { return {
"session data is not modified until after sync": async (assert) => { "session data is not modified until after sync": async (assert) => {
const session = new Session({storage: createStorageMock({ const session = new Session({storage: createStorageMock({
syncToken: "a", sync: {token: "a", filterId: 5}
syncFilterId: 5,
}), sessionInfo: {userId: ""}}); }), sessionInfo: {userId: ""}});
await session.load(); await session.load();
let txnSetCalled = false; let syncSet = false;
const syncTxn = { const syncTxn = {
session: { session: {
set({syncToken, syncFilterId}) { set(key, value) {
txnSetCalled = true; if (key === "sync") {
assert.equal(syncToken, "b"); assert.equal(value.token, "b");
assert.equal(syncFilterId, 6); assert.equal(value.filterId, 6);
syncSet = true;
}
} }
} }
}; };
const newSessionData = session.writeSync("b", 6, {}, syncTxn); const newSessionData = session.writeSync("b", 6, {}, syncTxn);
assert(txnSetCalled); assert(syncSet);
assert.equal(session.syncToken, "a"); assert.equal(session.syncToken, "a");
assert.equal(session.syncFilterId, 5); assert.equal(session.syncFilterId, 5);
session.afterSync(newSessionData); session.afterSync(newSessionData);

View file

@ -263,7 +263,7 @@ export function tests() {
"membership trigger change": function(assert) { "membership trigger change": function(assert) {
const summary = new RoomSummary("id"); const summary = new RoomSummary("id");
let written = false; let written = false;
const changes = summary.writeSync({}, "join", {roomSummary: {set: () => { written = true; }}}); const changes = summary.writeSync({}, "join", false, false, {roomSummary: {set: () => { written = true; }}});
assert(changes); assert(changes);
assert(written); assert(written);
assert.equal(changes.membership, "join"); assert.equal(changes.membership, "join");

View file

@ -1,12 +1,14 @@
import {iterateCursor} from "./utils.js"; import {iterateCursor, reqAsPromise} from "./utils.js";
import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js"; import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js";
import {RoomMemberStore} from "./stores/RoomMemberStore.js"; import {RoomMemberStore} from "./stores/RoomMemberStore.js";
import {SessionStore} from "./stores/SessionStore.js";
// FUNCTIONS SHOULD ONLY BE APPENDED!! // FUNCTIONS SHOULD ONLY BE APPENDED!!
// the index in the array is the database version // the index in the array is the database version
export const schema = [ export const schema = [
createInitialStores, createInitialStores,
createMemberStore, createMemberStore,
migrateSession,
]; ];
// TODO: how to deal with git merge conflicts of this array? // TODO: how to deal with git merge conflicts of this array?
@ -44,3 +46,21 @@ async function createMemberStore(db, txn) {
} }
}); });
} }
async function migrateSession(db, txn) {
const session = txn.objectStore("session");
try {
const PRE_MIGRATION_KEY = 1;
const entry = await reqAsPromise(session.get(PRE_MIGRATION_KEY));
if (entry) {
session.delete(PRE_MIGRATION_KEY);
const {syncToken, syncFilterId, serverVersions} = entry.value;
const store = new SessionStore(session);
store.set("sync", {token: syncToken, filterId: syncFilterId});
store.set("serverVersions", serverVersions);
}
} catch (err) {
txn.abort();
console.error("could not migrate session", err.stack);
}
}

View file

@ -35,14 +35,14 @@ export class SessionStore {
this._sessionStore = sessionStore; this._sessionStore = sessionStore;
} }
async get() { async get(key) {
const session = await this._sessionStore.selectFirst(IDBKeyRange.only(1)); const entry = await this._sessionStore.get(key);
if (session) { if (entry) {
return session.value; return entry.value;
} }
} }
set(session) { set(key, value) {
return this._sessionStore.put({key: 1, value: session}); return this._sessionStore.put({key, value});
} }
} }