Skip to content

Commit 5689f65

Browse files
committed
raise limits on hot sync; make explicit remote scan much more efficient and scalable (in terms of number of files)
1 parent a0990f5 commit 5689f65

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export const CLI_NAME = "reflect-sync";
22
export const SOFTWARE_NAME = "ReflectSync";
33

4-
export const MAX_WATCHERS = Number(process.env.REFLECT_MAX_WATCHERS ?? 64);
4+
export const MAX_WATCHERS = Number(process.env.REFLECT_MAX_WATCHERS ?? 128);

src/scan.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ export function configureScanCommand(
114114
collectListOption,
115115
[] as string[],
116116
)
117+
.option(
118+
"--restricted-paths-stdin",
119+
"read NUL-separated restricted paths from stdin",
120+
false,
121+
)
117122
.option("--numeric-ids", "include uid and gid in file hashes", false)
118123
.option(
119124
"-i, --ignore <pattern>",
@@ -167,6 +172,7 @@ type ScanOptions = {
167172
ignoreRules?: string[];
168173
ignore?: string[];
169174
restrictedPaths?: string[];
175+
restrictedPathsStdin?: boolean;
170176
logicalClock?: LogicalClock;
171177
clockBase?: string[];
172178
scanTick?: number;
@@ -191,6 +197,7 @@ export async function runScan(opts: ScanOptions): Promise<void> {
191197
ignoreRules: ignoreRulesOpt = [],
192198
ignore: ignoreCliOpt = [],
193199
restrictedPaths = [],
200+
restrictedPathsStdin = false,
194201
logicalClock,
195202
scanTick: scanTickOverride,
196203
filesystemCaps: providedCaps,
@@ -239,8 +246,13 @@ export async function runScan(opts: ScanOptions): Promise<void> {
239246
ignoreRaw.push(...autoIgnoreForRoot(absRoot, syncHome));
240247
const ignoreRules = normalizeIgnorePatterns(ignoreRaw);
241248

249+
const stdinRestricted: string[] = [];
250+
if (restrictedPathsStdin) {
251+
const buf = await readPathsFromStdin();
252+
stdinRestricted.push(...buf);
253+
}
242254
const restrictedPathList = dedupeRestrictedList(
243-
includeAncestors(restrictedPaths),
255+
includeAncestors([...restrictedPaths, ...stdinRestricted]),
244256
);
245257
const hasRestrictions = restrictedPathList.length > 0;
246258

@@ -1536,6 +1548,20 @@ export async function runScan(opts: ScanOptions): Promise<void> {
15361548
}
15371549
}
15381550
1551+
async function readPathsFromStdin(): Promise<string[]> {
1552+
return new Promise((resolve) => {
1553+
const chunks: Buffer[] = [];
1554+
process.stdin.on("data", (chunk) => chunks.push(chunk as Buffer));
1555+
process.stdin.on("end", () => {
1556+
if (chunks.length === 0) return resolve([]);
1557+
const buf = Buffer.concat(chunks);
1558+
const parts = buf.toString("utf8").split("\u0000");
1559+
resolve(parts.filter(Boolean));
1560+
});
1561+
process.stdin.resume();
1562+
});
1563+
}
1564+
15391565
// ---------- CLI entry (preserved) ----------
15401566
cliEntrypoint<
15411567
ScanOptions & {

src/scheduler.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const PRUNE_REMOTE_DATABASE_MS = 30_000;
9494

9595
// never sync more than this many files at once using hot sync
9696
// (discards more)
97-
const MAX_HOT_SYNC = 200;
97+
const MAX_HOT_SYNC = 1_000;
9898

9999
class FatalSchedulerError extends Error {
100100
constructor(message: string) {
@@ -137,6 +137,7 @@ export type SchedulerOptions = {
137137

138138
type CycleOptions = {
139139
restrictedPaths?: string[];
140+
restrictedPathsFromStdin?: boolean;
140141
label?: string;
141142
};
142143

@@ -910,6 +911,7 @@ export async function runScheduler({
910911
numericIds?: boolean;
911912
ignoreRules: string[];
912913
restrictedPaths?: string[];
914+
restrictedPathsStdin?: boolean;
913915
scanTick?: number;
914916
markCaseConflicts?: boolean;
915917
caseConflictCaps?: FilesystemCapabilities;
@@ -955,12 +957,18 @@ export async function runScheduler({
955957
sshArgs.push("--emit-since-age");
956958
sshArgs.push(`${Date.now() - lastRemoteScan.whenOk}`);
957959
}
958-
if (params.restrictedPaths?.length) {
960+
const stdinPaths = params.restrictedPathsStdin
961+
? (params.restrictedPaths ?? [])
962+
: [];
963+
if (params.restrictedPaths?.length && !params.restrictedPathsStdin) {
959964
for (const rel of params.restrictedPaths) {
960965
if (!rel) continue;
961966
sshArgs.push("--restricted-path", rel);
962967
}
963968
}
969+
if (stdinPaths.length) {
970+
sshArgs.push("--restricted-paths-stdin");
971+
}
964972
if (params.markCaseConflicts) {
965973
sshArgs.push("--mark-case-conflicts");
966974
if (params.caseConflictCaps?.caseInsensitive) {
@@ -988,8 +996,13 @@ export async function runScheduler({
988996
);
989997

990998
const sshP = spawn("ssh", sshArgs, {
991-
stdio: ["ignore", "pipe", "pipe"],
999+
stdio: params.restrictedPathsStdin
1000+
? ["pipe", "pipe", "pipe"]
1001+
: ["ignore", "pipe", "pipe"],
9921002
});
1003+
if (stdinPaths.length && sshP.stdin) {
1004+
sshP.stdin.end(stdinPaths.join("\u0000"));
1005+
}
9931006
const stderrChunks: string[] = [];
9941007
sshP.stderr?.on("data", (chunk) => {
9951008
const text = chunk.toString();
@@ -1692,6 +1705,7 @@ export async function runScheduler({
16921705
if (!expandedRestricted.length) return;
16931706
await runCycle({
16941707
restrictedPaths: expandedRestricted,
1708+
restrictedPathsFromStdin: alphaIsRemote || betaIsRemote,
16951709
label: "hot",
16961710
});
16971711
} catch (e: any) {
@@ -1973,6 +1987,7 @@ export async function runScheduler({
19731987
numericIds,
19741988
ignoreRules,
19751989
restrictedPaths,
1990+
restrictedPathsStdin: options.restrictedPathsFromStdin,
19761991
scanTick,
19771992
markCaseConflicts: markAlphaConflicts,
19781993
caseConflictCaps: alphaCaseConflictCaps,
@@ -2051,6 +2066,8 @@ export async function runScheduler({
20512066
numericIds,
20522067
ignoreRules,
20532068
restrictedPaths: hasRestrictions ? restrictedPaths : undefined,
2069+
restrictedPathsStdin:
2070+
options.restrictedPathsFromStdin && hasRestrictions,
20542071
scanTick,
20552072
markCaseConflicts: markBetaConflicts,
20562073
caseConflictCaps: betaCaseConflictCaps,
@@ -2395,7 +2412,11 @@ export async function runScheduler({
23952412
while (1) {
23962413
let status;
23972414
if (restrictedPaths?.length) {
2398-
status = await runCycle({ restrictedPaths, label: "hot" });
2415+
status = await runCycle({
2416+
restrictedPaths,
2417+
restrictedPathsFromStdin: alphaIsRemote || betaIsRemote,
2418+
label: "hot",
2419+
});
23992420
} else {
24002421
status = await runCycle();
24012422
}

0 commit comments

Comments
 (0)