@openrewrite/rewrite 8.87.3 → 8.87.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,7 +38,7 @@ import {
38
38
  } from "./request";
39
39
  import {DataTableStore} from "../data-table";
40
40
  import {RecipeMarketplace} from "../marketplace";
41
- import {initializeMetricsCsv} from "./request/metrics";
41
+ import {initializeMetricsCsv, setCacheSizeProvider} from "./request/metrics";
42
42
  import {RpcObjectData, RpcObjectState, RpcReceiveQueue} from "./queue";
43
43
  import {RpcRecipe} from "./recipe";
44
44
  import {ExecutionContext} from "../execution";
@@ -74,6 +74,10 @@ export class RewriteRpc {
74
74
  readonly remoteRefs: Map<number, any> = new Map();
75
75
  readonly localRefs: ReferenceMap = new ReferenceMap();
76
76
 
77
+ // Ref high-water per source file, captured before it is first visited so an Evict rolls
78
+ // back exactly the refs it introduced. `send` = localRefs snapshot, `recvMax` = max remoteRefs key.
79
+ readonly refCheckpoints: Map<string, { send: number, recvMax: number }> = new Map();
80
+
77
81
  private remoteLanguages?: string[];
78
82
  private readonly logger?: rpc.Logger;
79
83
  private traceGetObject: TraceGetObject = {receive: false, send: false};
@@ -93,6 +97,11 @@ export class RewriteRpc {
93
97
  }) {
94
98
  // Initialize metrics CSV file if configured
95
99
  initializeMetricsCsv(options.metricsCsv, options.logger);
100
+ setCacheSizeProvider(() => ({
101
+ local: this.localObjects.size,
102
+ remote: this.remoteObjects.size,
103
+ refs: this.remoteRefs.size + this.localRefs.size,
104
+ }));
96
105
  this.logger = options.logger;
97
106
 
98
107
  const preparedRecipes: Map<String, Recipe> = new Map();
@@ -101,6 +110,19 @@ export class RewriteRpc {
101
110
  // Need this indirection, otherwise `this` will be undefined when executed in the handlers.
102
111
  const getObject = (id: string, sourceFileType?: string) => this.getObject(id, sourceFileType);
103
112
  const getCursor = (cursorIds: string[] | undefined, sourceFileType?: string) => this.getCursor(cursorIds, sourceFileType);
113
+ // First visit of the file wins.
114
+ const captureRefCheckpoint = (treeId: string) => {
115
+ if (this.refCheckpoints.has(treeId)) {
116
+ return;
117
+ }
118
+ let recvMax = -1;
119
+ for (const k of this.remoteRefs.keys()) {
120
+ if (k > recvMax) {
121
+ recvMax = k;
122
+ }
123
+ }
124
+ this.refCheckpoints.set(treeId, {send: this.localRefs.snapshot(), recvMax});
125
+ };
104
126
  const traceGetObject = () => this.traceGetObject.send;
105
127
  const dataTableStore = () => this.configuredDataTableStore;
106
128
 
@@ -109,8 +131,8 @@ export class RewriteRpc {
109
131
  // GetMarketplace builds rows so the host can attribute each recipe to its own bundle.
110
132
  const recipeOrigin: Map<string, string> = new Map();
111
133
 
112
- Visit.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, getCursor, dataTableStore, options.metricsCsv);
113
- BatchVisit.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, getCursor, dataTableStore, options.metricsCsv);
134
+ Visit.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, captureRefCheckpoint, getCursor, dataTableStore, options.metricsCsv);
135
+ BatchVisit.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, captureRefCheckpoint, getCursor, dataTableStore, options.metricsCsv);
114
136
  Generate.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, dataTableStore, options.metricsCsv);
115
137
  SetDataTableStore.handle(this.connection, store => this.configuredDataTableStore = store, options.metricsCsv);
116
138
  GetObject.handle(this.connection, this.remoteObjects, this.localObjects,
@@ -140,6 +162,7 @@ export class RewriteRpc {
140
162
  this.remoteObjects.clear();
141
163
  this.remoteRefs.clear();
142
164
  this.localRefs.clear();
165
+ this.refCheckpoints.clear();
143
166
  preparedRecipes.clear();
144
167
  this.remoteLanguages = undefined;
145
168
  };
@@ -156,6 +179,27 @@ export class RewriteRpc {
156
179
  }
157
180
  )
158
181
 
182
+ // Drop one source file's tree + roll back the refs it introduced. Fire-and-forget
183
+ // notification (no reply), so recipe/accumulator/context state is left intact.
184
+ this.connection.onNotification(
185
+ new rpc.NotificationType<{ id: string }>("Evict"),
186
+ (params) => {
187
+ const id = params.id;
188
+ this.localObjects.delete(id);
189
+ this.remoteObjects.delete(id);
190
+ const cp = this.refCheckpoints.get(id);
191
+ if (cp !== undefined) {
192
+ this.localRefs.rollbackTo(cp.send);
193
+ for (const k of [...this.remoteRefs.keys()]) {
194
+ if (k > cp.recvMax) {
195
+ this.remoteRefs.delete(k);
196
+ }
197
+ }
198
+ this.refCheckpoints.delete(id);
199
+ }
200
+ }
201
+ )
202
+
159
203
  RewriteRpc.set(this);
160
204
  this.connection.listen();
161
205
  }