fix(perf): Apply accountId to more queries, always run query plans in dev mode to flag SCANs

This commit is contained in:
Ben Gotow 2015-08-26 14:10:28 -07:00
parent f33035cfc3
commit 41a3529f16
12 changed files with 66 additions and 26 deletions

View file

@ -1,8 +1,8 @@
FileFrame = require "./file-frame"
FileList = require './file-list'
FileSelectionBar = require './file-selection-bar'
{ComponentRegistry,
WorkspaceStore} = require 'nylas-exports'
# FileFrame = require "./file-frame"
# FileList = require './file-list'
# FileSelectionBar = require './file-selection-bar'
# {ComponentRegistry,
# WorkspaceStore} = require 'nylas-exports'
module.exports =

View file

@ -3,6 +3,7 @@ Reflux = require 'reflux'
Contact,
Thread,
DatabaseStore,
AccountStore,
ContactStore} = require 'nylas-exports'
_ = require 'underscore'
@ -60,7 +61,9 @@ SearchSuggestionStore = Reflux.createStore
return if @_threadQueryInFlight
@_threadQueryInFlight = true
DatabaseStore.findAll(Thread, [Thread.attributes.subject.like(val)])
DatabaseStore.findAll(Thread)
.where(Thread.attributes.subject.like(val))
.where(Thread.attributes.accountId.equal(AccountStore.current().id))
.order(Thread.attributes.lastMessageReceivedTimestamp.descending())
.limit(4)
.then (results) =>

View file

@ -1,7 +1,11 @@
_ = require 'underscore'
Reflux = require 'reflux'
request = require 'request'
{Contact, ContactStore, DatabaseStore, FocusedContactsStore} = require 'nylas-exports'
{Contact,
AccountStore
ContactStore,
DatabaseStore,
FocusedContactsStore} = require 'nylas-exports'
module.exports =
FullContactStore = Reflux.createStore
@ -22,9 +26,10 @@ FullContactStore = Reflux.createStore
# for the contact, we get it anew.
_loadFocusedContact: ->
contact = FocusedContactsStore.focusedContact()
account = AccountStore.current()
if contact
@_resolvedFocusedContact = contact
DatabaseStore.findBy(Contact, email: contact.email).then (contact) =>
DatabaseStore.findBy(Contact, {email: contact.email, accountId: account.id}).then (contact) =>
@_resolvedFocusedContact = contact
if contact and not contact.thirdPartyData?["FullContact"]?
@_loadContactDataFromAPI(contact)

View file

@ -84,7 +84,10 @@ class ThreadListStore extends NylasStore
else
throw new Error("Invalid organizationUnit")
view = new DatabaseView Thread, {matchers}, (ids) =>
DatabaseStore.findAll(Message).where(Message.attributes.threadId.in(ids)).then (messages) ->
DatabaseStore.findAll(Message)
.where(Message.attributes.threadId.in(ids))
.where(Message.attributes.accountId.equal(account.id))
.then (messages) ->
messagesByThread = {}
for id in ids
messagesByThread[id] = []

View file

@ -3,7 +3,7 @@ Thread = require '../../src/flux/models/thread'
FocusedContentStore = require '../../src/flux/stores/focused-content-store'
Actions = require '../../src/flux/actions'
testThread = new Thread(id: '123')
testThread = new Thread(id: '123', accountId: 'abc')
describe "FocusedContentStore", ->
describe "onSetFocus", ->

View file

@ -30,6 +30,7 @@ describe "MessageStore", ->
spyOn(DatabaseStore, 'findAll').andCallFake ->
include: -> @
waitForAnimations: -> @
where: -> @
then: (callback) -> callback([testMessage1, testMessage2])
it "should retrieve the focused thread", ->

View file

@ -19,7 +19,7 @@ describe "UnreadCountStore", ->
atom.testOrganizationUnit = 'folder'
UnreadCountStore._fetchCount()
advanceClock()
expect(DatabaseStore.findBy).toHaveBeenCalledWith(Folder, {name: 'inbox'})
expect(DatabaseStore.findBy).toHaveBeenCalledWith(Folder, {name: 'inbox', accountId: 'test_account_id'})
[Model, Matchers] = DatabaseStore.count.calls[0].args
expect(Model).toBe(Thread)
@ -33,7 +33,7 @@ describe "UnreadCountStore", ->
atom.testOrganizationUnit = 'label'
UnreadCountStore._fetchCount()
advanceClock()
expect(DatabaseStore.findBy).toHaveBeenCalledWith(Label, {name: 'inbox'})
expect(DatabaseStore.findBy).toHaveBeenCalledWith(Label, {name: 'inbox', accountId: 'test_account_id'})
[Model, Matchers] = DatabaseStore.count.calls[0].args
expect(Matchers[0].attr.modelKey).toBe('accountId')

View file

@ -11,10 +11,6 @@ class Event extends Model
modelKey: 'id'
jsonKey: 'id'
'accountId': Attributes.String
modelKey: 'accountId'
jsonKey: 'accountId'
'title': Attributes.String
modelKey: 'title'
jsonKey: 'title'

View file

@ -17,7 +17,7 @@ PriorityUICoordinator = require '../../priority-ui-coordinator'
generateTempId,
isTempId} = require '../models/utils'
DatabaseVersion = 9
DatabaseVersion = 10
DatabasePhase =
Setup: 'setup'
@ -25,7 +25,8 @@ DatabasePhase =
Close: 'close'
DEBUG_TO_LOG = false
DEBUG_QUERY_PLANS = false
DEBUG_QUERY_PLANS = atom.inDevMode()
DEBUG_MISSING_ACCOUNT_ID = false
BEGIN_TRANSACTION = 'BEGIN TRANSACTION'
COMMIT = 'COMMIT'
@ -168,6 +169,30 @@ class DatabaseStore extends NylasStore
app = require('remote').getGlobal('application')
app.rebuildDatabase()
_prettyConsoleLog: (q) =>
q = "color:black |||%c " + q
q = q.replace(/`(\w+)`/g, "||| color:purple |||%c$&||| color:black |||%c")
colorRules =
'color:green': ['SELECT', 'INSERT INTO', 'VALUES', 'WHERE', 'FROM', 'JOIN', 'ORDER BY', 'DESC', 'ASC', 'INNER', 'OUTER', 'LIMIT', 'OFFSET', 'IN']
'color:red; background-color:#ffdddd;': ['SCAN TABLE']
for style, keywords of colorRules
for keyword in keywords
q = q.replace(new RegExp("\\b#{keyword}\\b", 'g'), "||| #{style} |||%c#{keyword}||| color:black |||%c")
q = q.split('|||')
colors = []
msg = []
for i in [0...q.length]
if i % 2 is 0
colors.push(q[i])
else
msg.push(q[i])
console.log(msg.join(''), colors...)
# Returns a promise that resolves when the query has been completed and
# rejects when the query has failed.
#
@ -185,9 +210,13 @@ class DatabaseStore extends NylasStore
else
fn = 'run'
if DEBUG_QUERY_PLANS and query.indexOf("SELECT ") is 0
if query.indexOf("SELECT ") is 0
if DEBUG_MISSING_ACCOUNT_ID and query.indexOf("`account_id`") is -1
@_prettyConsoleLog("QUERY does not specify accountId: #{query}")
if DEBUG_QUERY_PLANS
@_db.all "EXPLAIN QUERY PLAN #{query}", values, (err, results) =>
console.log(results.map((row) -> row.detail).join('\n') + " for " + query)
str = results.map((row) -> row.detail).join('\n') + " for " + query
@_prettyConsoleLog(str) if str.indexOf("SCAN") isnt -1
# Important: once the user begins a transaction, queries need to run in serial.
# This ensures that the subsequent "COMMIT" call actually runs after the other

View file

@ -34,7 +34,8 @@ class EventStore extends NylasStore
constructor: ->
@_eventCache = {}
@_accountId = null
@_accountId = AccountStore.current()?.id
@listenTo DatabaseStore, @_onDatabaseChanged
@listenTo AccountStore, @_onAccountChanged
@ -48,9 +49,10 @@ class EventStore extends NylasStore
Actions.queueTask(task)
__refreshCache: =>
return unless @_accountId
new Promise (resolve, reject) =>
DatabaseStore.findAll(Event)
.then (events=[]) =>
DatabaseStore.findAll(Event, {accountId: @_accountId}).then (events=[]) =>
@_eventCache[e.id] = e for e in events
@trigger()
resolve()

View file

@ -140,7 +140,8 @@ class MessageStore extends NylasStore
return unless @_thread
loadedThreadId = @_thread.id
query = DatabaseStore.findAll(Message, threadId: loadedThreadId)
query = DatabaseStore.findAll(Message)
query.where(threadId: loadedThreadId, accountId: @_thread.accountId)
query.include(Message.attributes.body)
query.then (items) =>
localIds = {}

View file

@ -58,7 +58,7 @@ UnreadCountStore = Reflux.createStore
# Note: We can't use the convenience methods on CategoryStore to fetch the
# category because it may not have been loaded yet
DatabaseStore.findBy(CategoryClass, {name: 'inbox'}).then (category) =>
DatabaseStore.findBy(CategoryClass, {name: 'inbox', accountId: account.id}).then (category) =>
return unless category
matchers = [