Skip to content

Commit e0d8d97

Browse files
authored
Revert fast-lane search isolate. (#8840)
1 parent 5004edb commit e0d8d97

File tree

8 files changed

+35
-128
lines changed

8 files changed

+35
-128
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ Important changes to data models, configuration, and migrations between each
22
AppEngine version, listed here to ease deployment and troubleshooting.
33

44
## Next Release (replace with git tag when deployed)
5+
* Bump runtimeVersion to `2025.07.01`.
6+
* Note: search instance uses single isolate for package queries. (reverted fast-lane isolate)
57

68
## `20250626t093300-all`
79
* Bump runtimeVersion to `2025.06.20`.

app/bin/tools/isolate_search_benchmark.dart

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,22 @@ final queries = [
2626
Future<void> main(List<String> args) async {
2727
print('Started. Current memory: ${ProcessInfo.currentRss ~/ 1024} KiB, '
2828
'max memory: ${ProcessInfo.maxRss ~/ 1024} KiB');
29-
final primaryRunner = await startSearchIsolate(snapshot: args.first);
30-
final reducedRunner = await startSearchIsolate(
31-
snapshot: args.first,
32-
removeTextContent: true,
33-
);
29+
final runner = await startSearchIsolate(snapshot: args.first);
3430
print('Loaded. Current memory: ${ProcessInfo.currentRss ~/ 1024} KiB, '
3531
'max memory: ${ProcessInfo.maxRss ~/ 1024} KiB');
3632

3733
for (var i = 0; i < 5; i++) {
38-
await _benchmark(primaryRunner, primaryRunner);
39-
await _benchmark(primaryRunner, reducedRunner);
34+
await _benchmark(runner);
4035
print('--');
4136
}
4237

43-
await primaryRunner.close();
44-
await reducedRunner.close();
38+
await runner.close();
4539
print('Done. Current memory: ${ProcessInfo.currentRss ~/ 1024} KiB, '
4640
'max memory: ${ProcessInfo.maxRss ~/ 1024} KiB');
4741
}
4842

49-
Future<void> _benchmark(IsolateRunner primary, IsolateRunner reduced) async {
50-
final index = IsolateSearchIndex(primary, reduced);
43+
Future<void> _benchmark(IsolateRunner primary) async {
44+
final index = IsolateSearchIndex(primary);
5145
final durations = <String, List<int>>{};
5246
for (var i = 0; i < 100; i++) {
5347
final random = Random(i);

app/lib/search/search_service.dart

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,29 +137,6 @@ class PackageDocument {
137137
Map<String, dynamic> toJson() => _$PackageDocumentToJson(this);
138138

139139
late final packageNameLowerCased = package.toLowerCase();
140-
141-
/// Removes the text-heavy content from the current object,
142-
/// making it lightweight for no-text indexing.
143-
PackageDocument removeTextContent() => PackageDocument(
144-
package: package,
145-
version: version,
146-
created: created,
147-
updated: updated,
148-
sourceUpdated: sourceUpdated,
149-
timestamp: timestamp,
150-
apiDocPages: null,
151-
dependencies: dependencies,
152-
description: null,
153-
downloadCount: downloadCount,
154-
downloadScore: downloadScore,
155-
grantedPoints: grantedPoints,
156-
likeCount: likeCount,
157-
likeScore: likeScore,
158-
maxPoints: maxPoints,
159-
readme: null,
160-
tags: tags,
161-
trendScore: trendScore,
162-
);
163140
}
164141

165142
/// A reference to an API doc page

app/lib/search/updater.dart

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,15 @@ IndexUpdater get indexUpdater => ss.lookup(#_indexUpdater) as IndexUpdater;
3030

3131
/// Loads a local search snapshot file and builds an in-memory package index from it.
3232
Future<InMemoryPackageIndex> loadInMemoryPackageIndexFromFile(
33-
String path, {
34-
bool removeTextContent = false,
35-
}) async {
33+
String path) async {
3634
final file = File(path);
3735
final content =
3836
json.decode(utf8.decode(gzip.decode(await file.readAsBytes())))
3937
as Map<String, Object?>;
4038
final snapshot = SearchSnapshot.fromJson(content);
4139
return InMemoryPackageIndex(
42-
documents: snapshot.documents!.values
43-
.where((d) => !isSdkPackage(d.package))
44-
.map((d) => removeTextContent ? d.removeTextContent() : d),
40+
documents:
41+
snapshot.documents!.values.where((d) => !isSdkPackage(d.package)),
4542
);
4643
}
4744

@@ -64,8 +61,8 @@ class IndexUpdater {
6461

6562
/// Loads the package index snapshot, or if it fails, creates a minimal
6663
/// package index with only package names and minimal information.
67-
Future<void> init({bool removeTextContent = false}) async {
68-
final isReady = await _initSnapshot(removeTextContent);
64+
Future<void> init() async {
65+
final isReady = await _initSnapshot();
6966
if (!isReady) {
7067
_logger.info('Loading minimum package index...');
7168
final documents = await searchBackend.loadMinimumPackageIndex().toList();
@@ -89,17 +86,14 @@ class IndexUpdater {
8986
}
9087

9188
/// Returns whether the snapshot was initialized and loaded properly.
92-
Future<bool> _initSnapshot(bool removeTextContent) async {
89+
Future<bool> _initSnapshot() async {
9390
try {
9491
_logger.info('Loading snapshot...');
9592
final documents = await searchBackend.fetchSnapshotDocuments();
9693
if (documents == null) {
9794
return false;
9895
}
99-
updatePackageIndex(InMemoryPackageIndex(
100-
documents:
101-
documents.map((d) => removeTextContent ? d.removeTextContent() : d),
102-
));
96+
updatePackageIndex(InMemoryPackageIndex(documents: documents));
10397
// Arbitrary sanity check that the snapshot is not entirely bogus.
10498
// Index merge will enable search.
10599
if (documents.length > 10) {

app/lib/service/entrypoint/search.dart

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,8 @@ class SearchCommand extends Command {
3838

3939
envConfig.checkServiceEnvironment(name);
4040
await withServices(() async {
41-
final primaryIsolate = await startSearchIsolate(logger: _logger);
42-
registerScopeExitCallback(primaryIsolate.close);
43-
44-
final reducedIsolate = await startSearchIsolate(
45-
logger: _logger,
46-
removeTextContent: true,
47-
);
48-
registerScopeExitCallback(reducedIsolate.close);
41+
final packageIsolate = await startSearchIsolate(logger: _logger);
42+
registerScopeExitCallback(packageIsolate.close);
4943

5044
final sdkIsolate = await startQueryIsolate(
5145
logger: _logger,
@@ -57,9 +51,8 @@ class SearchCommand extends Command {
5751

5852
registerSearchIndex(
5953
SearchResultCombiner(
60-
primaryIndex: LatencyAwareSearchIndex(
61-
IsolateSearchIndex(primaryIsolate, reducedIsolate),
62-
),
54+
primaryIndex:
55+
LatencyAwareSearchIndex(IsolateSearchIndex(packageIsolate)),
6356
sdkIndex: SdkIsolateIndex(sdkIsolate),
6457
),
6558
);
@@ -72,10 +65,7 @@ class SearchCommand extends Command {
7265
await Future.delayed(delay);
7366

7467
// create a new index and handover with a 2-minute maximum wait
75-
await Future.wait([
76-
primaryIsolate.renew(count: 1, wait: Duration(minutes: 2)),
77-
reducedIsolate.renew(count: 1, wait: Duration(minutes: 2)),
78-
]);
68+
await packageIsolate.renew(count: 1, wait: Duration(minutes: 2));
7969

8070
// schedule the renewal again
8171
scheduleRenew();

app/lib/service/entrypoint/search_index.dart

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ import 'package:pub_dev/shared/utils.dart';
2222
final _logger = Logger('search_index');
2323

2424
final _argParser = ArgParser()
25-
..addFlag(
26-
'remove-text-content',
27-
defaultsTo: false,
28-
help: 'When set, the text content of the index will be removed.',
29-
)
3025
..addOption(
3126
'snapshot',
3227
help:
@@ -39,7 +34,6 @@ Future<void> main(List<String> args, var message) async {
3934

4035
final argv = _argParser.parse(args);
4136
final snapshot = argv['snapshot'] as String?;
42-
final removeTextContent = (argv['remove-text-content'] as bool?) ?? false;
4337

4438
final ServicesWrapperFn servicesWrapperFn;
4539
if (envConfig.isRunningInAppengine) {
@@ -52,10 +46,9 @@ Future<void> main(List<String> args, var message) async {
5246
await fork(() async {
5347
await servicesWrapperFn(() async {
5448
if (snapshot == null) {
55-
await indexUpdater.init(removeTextContent: removeTextContent);
49+
await indexUpdater.init();
5650
} else {
57-
updatePackageIndex(await loadInMemoryPackageIndexFromFile(snapshot,
58-
removeTextContent: removeTextContent));
51+
updatePackageIndex(await loadInMemoryPackageIndexFromFile(snapshot));
5952
}
6053

6154
await runIsolateFunctions(
@@ -85,16 +78,14 @@ Future<void> main(List<String> args, var message) async {
8578
/// Starts a new search isolate with optional overrides.
8679
Future<IsolateRunner> startSearchIsolate({
8780
Logger? logger,
88-
bool removeTextContent = false,
8981
String? snapshot,
9082
}) async {
9183
return await startQueryIsolate(
9284
logger: logger ?? _logger,
93-
kind: removeTextContent ? 'reduced' : 'primary',
85+
kind: 'package',
9486
spawnUri: Uri.parse('package:pub_dev/service/entrypoint/search_index.dart'),
9587
spawnArgs: [
9688
if (snapshot != null) ...['--snapshot', snapshot],
97-
if (removeTextContent) '--remove-text-content',
9889
],
9990
);
10091
}
@@ -103,9 +94,8 @@ Future<IsolateRunner> startSearchIsolate({
10394
/// across isolate boundaries. The instance should be registered inside the
10495
/// `frontend` isolate, and it calls the `index` isolate as a delegate.
10596
class IsolateSearchIndex implements SearchIndex {
106-
final IsolateRunner _primary;
107-
final IsolateRunner _reduced;
108-
IsolateSearchIndex(this._primary, this._reduced);
97+
final IsolateRunner _runner;
98+
IsolateSearchIndex(this._runner);
10999
var _isReady = false;
110100

111101
@override
@@ -121,7 +111,7 @@ class IsolateSearchIndex implements SearchIndex {
121111
@override
122112
FutureOr<IndexInfo> indexInfo() async {
123113
try {
124-
final info = await _primary.sendRequest(
114+
final info = await _runner.sendRequest(
125115
'info',
126116
timeout: Duration(seconds: 5),
127117
);
@@ -139,8 +129,7 @@ class IsolateSearchIndex implements SearchIndex {
139129
@override
140130
FutureOr<PackageSearchResult> search(ServiceSearchQuery query) async {
141131
try {
142-
final runner = query.parsedQuery.hasFreeText ? _primary : _reduced;
143-
final rs = await runner.sendRequest(
132+
final rs = await _runner.sendRequest(
144133
Uri(queryParameters: query.toUriQueryParameters()).toString(),
145134
timeout: Duration(minutes: 1),
146135
);

app/lib/shared/versions.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ final RegExp runtimeVersionPattern = RegExp(r'^\d{4}\.\d{2}\.\d{2}$');
2424
/// when the version switch happens.
2525
const _acceptedRuntimeVersions = <String>[
2626
// The current [runtimeVersion].
27-
'2025.06.20',
27+
'2025.07.01',
2828
// Fallback runtime versions.
29+
'2025.06.20',
2930
'2025.06.03',
30-
'2025.06.02',
3131
];
3232

3333
/// Sets the current runtime versions.

app/test/service/entrypoint/search_index_test.dart

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,15 @@ import 'package:test/test.dart';
1212

1313
void main() {
1414
group('Search index inside an isolate', () {
15-
late IsolateRunner primaryRunner;
16-
late IsolateRunner reducedRunner;
15+
late IsolateRunner runner;
1716

1817
tearDown(() async {
19-
await primaryRunner.close();
20-
await reducedRunner.close();
18+
await runner.close();
2119
});
2220

2321
test('start and work with local index', () async {
2422
await withTempDirectory((tempDir) async {
25-
// NOTE: The primary and the reduced index loads two different dataset,
26-
// in order to make the testing of the executation path unambigious.
27-
final primaryPath = p.join(tempDir.path, 'primary.json.gz');
23+
final snapshotPath = p.join(tempDir.path, 'snapshot.json.gz');
2824
await saveInMemoryPackageIndexToFile(
2925
[
3026
PackageDocument(
@@ -33,36 +29,16 @@ void main() {
3329
tags: ['sdk:dart'],
3430
),
3531
],
36-
primaryPath,
32+
snapshotPath,
3733
);
3834

39-
primaryRunner = await startSearchIsolate(snapshot: primaryPath);
40-
41-
final reducedPath = p.join(tempDir.path, 'reduced.json.gz');
42-
await saveInMemoryPackageIndexToFile(
43-
[
44-
PackageDocument(
45-
package: 'reduced_json_annotation',
46-
description: 'Annotation metadata for JSON serialization.',
47-
tags: ['sdk:dart'],
48-
downloadScore: 1.0,
49-
maxPoints: 100,
50-
grantedPoints: 100,
51-
),
52-
],
53-
reducedPath,
54-
);
55-
56-
reducedRunner = await startSearchIsolate(
57-
snapshot: reducedPath,
58-
removeTextContent: true,
59-
);
35+
runner = await startSearchIsolate(snapshot: snapshotPath);
6036

6137
// index calling the sendport
62-
final searchIndex = IsolateSearchIndex(primaryRunner, reducedRunner);
38+
final searchIndex = IsolateSearchIndex(runner);
6339
expect(await searchIndex.isReady(), true);
6440

65-
// text query - result from primary index
41+
// text query - result from package index
6642
final rs =
6743
await searchIndex.search(ServiceSearchQuery.parse(query: 'json'));
6844
expect(rs.toJson(), {
@@ -76,21 +52,6 @@ void main() {
7652
},
7753
],
7854
});
79-
80-
// predicate query - result from reduced index
81-
final rs2 = await searchIndex
82-
.search(ServiceSearchQuery.parse(query: 'sdk:dart'));
83-
expect(rs2.toJson(), {
84-
'timestamp': isNotEmpty,
85-
'totalCount': 1,
86-
'sdkLibraryHits': [],
87-
'packageHits': [
88-
{
89-
'package': 'reduced_json_annotation',
90-
'score': greaterThan(0.5),
91-
},
92-
],
93-
});
9455
});
9556
}, timeout: Timeout(Duration(minutes: 5)));
9657
});

0 commit comments

Comments
 (0)