Skip to content

Commit

Permalink
core/local/atom: Migrate Windows updated_at dates
Browse files Browse the repository at this point in the history
  Stat dates on Windows were previously truncated to the second while
  we now get the milliseconds as well.
  To avoid re-calculating all the local checksums during the initial
  scan because of the date migration, we'll truncate `scan` events
  dates to the second during the first initial scan following the
  publication of v3.28.1 when checking if the checksum of a given file
  can be reused or not.

  When publishing v3.28.2 or greater, we can remove
  `WINDOWS_DATE_MIGRATION_FLAG` and stop truncating dates during the
  initial scan.

  Users who will have skipped the version introducing the flag will
  see all their checksums re-computed.
  • Loading branch information
taratatach committed Jul 6, 2021
1 parent 135ea19 commit d9c069f
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 25 deletions.
18 changes: 18 additions & 0 deletions core/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const url = require('url')
const uuid = require('uuid/v4')
const https = require('https')
const { createGzip } = require('zlib')
const semver = require('semver')

require('./globals')
const pkg = require('../package.json')
Expand Down Expand Up @@ -373,6 +374,23 @@ class App {
)
wasUpdated = false
}

// TODO: remove with flag WINDOWS_DATE_MIGRATION_FLAG
try {
if (
semver.lt(
clientInfo.configVersion,
config.WINDOWS_DATE_MIGRATION_APP_VERSION
)
) {
this.config.setFlag(config.WINDOWS_DATE_MIGRATION_FLAG, true)
}
} catch (err) {
log.error(
{ err, sentry: true },
`could not set ${config.WINDOWS_DATE_MIGRATION_FLAG} flag`
)
}
}

this.instanciate()
Expand Down
36 changes: 36 additions & 0 deletions core/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ export type WatcherType = 'atom' | 'chokidar'
type FileConfig = Object
*/

/* Stat dates on Windows were previously truncated to the second while we now
* get the milliseconds as well.
* To avoid re-calculating all the local checksums during the initial scan
* because of the date migration, we'll truncate `scan` events dates to the
* second during the first initial scan following the publication of v3.28.1
* when checking if the checksum of a given file can be reused or not.
*
* When publishing v3.28.2 or greater, we can remove WINDOWS_DATE_MIGRATION_FLAG
* and stop truncating dates during the initial scan.
*
* Users who will have skipped the version introducing the flag will see all
* their checksums re-computed.
*/
const WINDOWS_DATE_MIGRATION_APP_VERSION = '3.28.1'
const WINDOWS_DATE_MIGRATION_FLAG = 'roundWindowsDatesToSecondInInitialDiff'

const INVALID_CONFIG_ERROR = 'InvalidConfigError'
const INVALID_CONFIG_MESSAGE = 'Invalid client configuration'
class InvalidConfigError extends Error {
Expand Down Expand Up @@ -170,6 +186,24 @@ class Config {
return _.get(this.fileConfig, 'flags', {})
}

isFlagActive(flagName /*: string */) /*: boolean */ {
return this.flags[flagName] || false
}

setFlag(flag /*: string */, isActive /*: boolean */) {
if (
typeof flag !== 'string' ||
typeof isActive !== 'boolean' ||
flag === ''
) {
throw new Error(
`Invalid flag or value: [String(${flag})] → "${String(isActive)}"`
)
}
_.set(this.fileConfig, `flags.${flag}`, isActive)
this.persist()
}

get version() /*: ?string */ {
return _.get(this.fileConfig, 'creds.client.softwareVersion', '')
}
Expand Down Expand Up @@ -288,6 +322,8 @@ function validateWatcherType(watcherType /*: ?string */) /*: ?WatcherType */ {

module.exports = {
INVALID_CONFIG_ERROR,
WINDOWS_DATE_MIGRATION_APP_VERSION,
WINDOWS_DATE_MIGRATION_FLAG,
InvalidConfigError,
Config,
environmentWatcherType,
Expand Down
9 changes: 8 additions & 1 deletion core/local/atom/dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const _ = require('lodash')

const winDetectMove = require('./win_detect_move')
const { buildDir, buildFile } = require('../../metadata')
const { WINDOWS_DATE_MIGRATION_FLAG } = require('../../config')
const logger = require('../../utils/logger')

const STEP_NAME = 'dispatch'
Expand All @@ -28,6 +29,7 @@ import type {
} from './event'
import type { WinDetectMoveState } from './win_detect_move'
import type EventEmitter from 'events'
import type { Config } from '../../config'
import type Prep from '../../prep'
import type { Pouch } from '../../pouch'
import type { Metadata } from '../../metadata'
Expand All @@ -41,6 +43,7 @@ type DispatchState = {
}
type DispatchOptions = {
config: Config,
events: EventEmitter,
prep: Prep,
pouch: Pouch,
Expand Down Expand Up @@ -133,8 +136,12 @@ async function dispatchEvent(
}

actions = {
initialScanDone: ({ events }) => {
initialScanDone: ({ config, events }) => {
log.info('Initial scan done')
// TODO: remove with flag WINDOWS_DATE_MIGRATION_FLAG
if (config.isFlagActive(WINDOWS_DATE_MIGRATION_FLAG)) {
config.setFlag(WINDOWS_DATE_MIGRATION_FLAG, false)
}
events.emit('initial-scan-done')
},

Expand Down
28 changes: 20 additions & 8 deletions core/local/atom/initial_diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
const _ = require('lodash')
const path = require('path')

const { WINDOWS_DATE_MIGRATION_FLAG } = require('../../config')
const { kind } = require('../../metadata')
const logger = require('../../utils/logger')
const Channel = require('./channel')

/*::
import type { Config } from '../../config'
import type { Pouch } from '../../pouch'
import type { AtomEvent, AtomBatch, EventKind } from './event'
import type { Metadata } from '../../metadata'
Expand Down Expand Up @@ -68,10 +70,10 @@ module.exports = {

function loop(
channel /*: Channel */,
opts /*: { pouch: Pouch, state: InitialDiffState } */
opts /*: { config: Config, state: InitialDiffState } */
) /*: Channel */ {
const out = new Channel()
initialDiff(channel, out, opts.state).catch(err => {
initialDiff(channel, out, opts).catch(err => {
log.warn({ err })
})
return out
Expand Down Expand Up @@ -126,7 +128,7 @@ function clearState(state /*: InitialDiffState */) {
async function initialDiff(
channel /*: Channel */,
out /*: Channel */,
state /*: InitialDiffState */
{ config, state } /*: { config: Config, state: InitialDiffState } */
) /*: Promise<void> */ {
// eslint-disable-next-line no-constant-condition
while (true) {
Expand All @@ -140,6 +142,10 @@ async function initialDiff(
initialScanDone
}
} = state
// TODO: remove with flag WINDOWS_DATE_MIGRATION_FLAG
const truncateWindowsDates = config.isFlagActive(
WINDOWS_DATE_MIGRATION_FLAG
)

if (initialScanDone) {
out.push(events)
Expand Down Expand Up @@ -189,7 +195,7 @@ async function initialDiff(
deletedIno: was.local.fileid || was.local.ino
})
}
} else if (foundUntouchedFile(event, was)) {
} else if (foundUntouchedFile(event, was, truncateWindowsDates)) {
_.set(event, [STEP_NAME, 'md5sumReusedFrom'], was.local.path)
event.md5sum = was.local.md5sum
}
Expand Down Expand Up @@ -338,8 +344,10 @@ function fixPathsAfterParentMove(renamedEvents, event) {
}
}

function contentUpdateTime(event) {
return event.stats.mtime.getTime()
function contentUpdateTime(event, truncateWindowsDates) {
return truncateWindowsDates
? event.stats.mtime.getTime() - event.stats.mtime.getMilliseconds()
: event.stats.mtime.getTime()
}

function docUpdateTime(oldLocal) {
Expand All @@ -354,12 +362,16 @@ function foundRenamedOrReplacedDoc(event, was) /*: boolean %checks */ {
return was != null && was.local != null && was.local.path !== event.path
}

function foundUntouchedFile(event, was) /*: boolean %checks */ {
function foundUntouchedFile(
event,
was,
truncateWindowsDates
) /*: boolean %checks */ {
return (
event.kind === 'file' &&
was != null &&
was.local != null &&
was.local.md5sum != null &&
contentUpdateTime(event) === docUpdateTime(was.local)
contentUpdateTime(event, truncateWindowsDates) === docUpdateTime(was.local)
)
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"react-markdown": "^4.3.1",
"read": "1.0.7",
"regedit": "^3.0.3",
"semver": "^7.3.2",
"uuid": "^3.3.2",
"yargs": "^11.0.0"
},
Expand Down
1 change: 1 addition & 0 deletions test/unit/local/atom/dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe('core/local/atom/dispatch.loop()', function() {
events = sinon.createStubInstance(SyncState)
prep = sinon.createStubInstance(Prep)
stepOptions = {
config: this.config,
events,
prep,
pouch: this.pouch,
Expand Down

0 comments on commit d9c069f

Please sign in to comment.