mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:59:47 +00:00
[vm/resident_frontend_server] Use File.create(exclusive:true) instead of links.
This makes resident frontend server more Windows-friendly, uses recently introduced api to ensure only one file creator succeeds. Fixes https://github.com/dart-lang/sdk/issues/49706 TEST=ci Change-Id: I520487f4f198cc2b2e9d656dca85607889723ef2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256543 Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
This commit is contained in:
parent
dfc82df6f7
commit
0e9b056f39
|
@ -10,8 +10,6 @@ import 'dart:io'
|
|||
exit,
|
||||
File,
|
||||
InternetAddress,
|
||||
Link,
|
||||
Platform,
|
||||
ProcessSignal,
|
||||
ServerSocket,
|
||||
Socket;
|
||||
|
@ -34,9 +32,7 @@ import '../frontend_server.dart';
|
|||
/// required.
|
||||
const _STAT_GRANULARITY = const Duration(seconds: 1);
|
||||
|
||||
const RESIDENT_SERVER_LINK_POSTFIX = '_link';
|
||||
|
||||
/// Ensures the symbolic link is removed if ctrl-C is sent to the server.
|
||||
/// Ensures the info file is removed if Ctrl-C is sent to the server.
|
||||
/// Mostly used when debugging.
|
||||
StreamSubscription<ProcessSignal> _cleanupHandler;
|
||||
|
||||
|
@ -427,24 +423,18 @@ Future<Map<String, dynamic>> sendAndReceiveResponse(
|
|||
}
|
||||
|
||||
/// Closes the ServerSocket and removes the [serverInfoFile] that is used
|
||||
/// to access this instance of the Resident Frontend Server as well as the
|
||||
/// lock to prevent the concurrent start race.
|
||||
/// to access this instance of the Resident Frontend Server.
|
||||
Future<void> residentServerCleanup(
|
||||
ServerSocket server, File serverInfoFile) async {
|
||||
final serverFilesystemLock =
|
||||
Link('${serverInfoFile.path}$RESIDENT_SERVER_LINK_POSTFIX');
|
||||
try {
|
||||
if (_cleanupHandler != null) {
|
||||
_cleanupHandler.cancel();
|
||||
}
|
||||
if (serverInfoFile.existsSync()) {
|
||||
serverInfoFile.deleteSync();
|
||||
}
|
||||
} catch (_) {
|
||||
} finally {
|
||||
try {
|
||||
if (serverFilesystemLock.existsSync()) {
|
||||
serverFilesystemLock.deleteSync();
|
||||
if (serverInfoFile.existsSync()) {
|
||||
serverInfoFile.deleteSync();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
@ -469,25 +459,10 @@ Future<StreamSubscription<Socket>> residentListenAndCompile(
|
|||
InternetAddress address, int port, File serverInfoFile,
|
||||
{Duration inactivityTimeout = const Duration(minutes: 30)}) async {
|
||||
ServerSocket server;
|
||||
// Create a link to the serverInfoFile to ensure that concurrent requests
|
||||
// to start the server result in only 1 server being started. This
|
||||
// also ensures that the serverInfoFile is only
|
||||
// visible once the server is started and ready to receive connections.
|
||||
// TODO https://github.com/dart-lang/sdk/issues/49647 use exclusive mode
|
||||
// on File objects
|
||||
final serverInfoLink =
|
||||
Link('${serverInfoFile.path}$RESIDENT_SERVER_LINK_POSTFIX');
|
||||
try {
|
||||
try {
|
||||
serverInfoLink.createSync(serverInfoFile.path);
|
||||
serverInfoFile.createSync(exclusive: true);
|
||||
} catch (e) {
|
||||
// TODO: https://github.com/dart-lang/sdk/issues/49647 Using a File
|
||||
// in exclusive mode removes the need for this check.
|
||||
if (Platform.isWindows && e.toString().contains('errno = 1314')) {
|
||||
throw StateError('Dart must be running in Administrator mode '
|
||||
'or Developer mode must be enabled when '
|
||||
'using the Resident Frontend Compiler.');
|
||||
}
|
||||
throw StateError('A server is already running.');
|
||||
}
|
||||
server = await ServerSocket.bind(address, port);
|
||||
|
@ -498,9 +473,9 @@ Future<StreamSubscription<Socket>> residentListenAndCompile(
|
|||
print('Error: $e\n');
|
||||
return null;
|
||||
} catch (e) {
|
||||
// lock was acquired but bind or writing failed
|
||||
// If we created a file, but bind or writing failed, clean up.
|
||||
try {
|
||||
serverInfoLink.deleteSync();
|
||||
serverInfoFile.deleteSync();
|
||||
} catch (_) {}
|
||||
print('Error: $e\n');
|
||||
return null;
|
||||
|
|
|
@ -577,9 +577,6 @@ void main() async {
|
|||
expect(serverSubscription, isNot(null));
|
||||
expect(startWhileAlreadyRunning, null);
|
||||
expect(serverInfo.existsSync(), true);
|
||||
expect(
|
||||
Link('${serverInfo.path}$RESIDENT_SERVER_LINK_POSTFIX').existsSync(),
|
||||
true);
|
||||
|
||||
final info = serverInfo.readAsStringSync();
|
||||
final address = InternetAddress(
|
||||
|
@ -590,9 +587,6 @@ void main() async {
|
|||
address, port, ResidentFrontendServer.shutdownCommand);
|
||||
expect(shutdownResult, equals(<String, dynamic>{"shutdown": true}));
|
||||
expect(serverInfo.existsSync(), false);
|
||||
expect(
|
||||
Link('${serverInfo.path}$RESIDENT_SERVER_LINK_POSTFIX').existsSync(),
|
||||
false);
|
||||
});
|
||||
|
||||
test('resident server starter', () async {
|
||||
|
|
Loading…
Reference in a new issue