dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.2k stars 1.57k forks source link

Disappeared lock after reading File contens. #31477

Open ngolovleva opened 6 years ago

ngolovleva commented 6 years ago

The codes below (lockSyncTest_lib.dart and lockSyncTest.dart) reproduce unexpected behaviour. The test lockSyncTest.dart fails when are executed on Linux platform, reporting:

Client failed, exit code 0 stdout: LOCK SUCCEEDED

stderr:

arguments: [.../lockSyncTest_lib.dart, /tmp/f1.txt]

Looks like calling "file.readAsBytesSync();" removes lock that was set with previous statement. When "file.readAsBytesSync();" is commented, test passes. Is it correct correct behavior or a bug?

Reproduced with Dart VM version: 2.0.0-dev.8.0 (Fri Nov 17 13:58:33 2017) on "linux_x64".

lockSyncTest_lib.dart file:

import "dart:io";

main(List<String> args) {
  File file = new File(args[0]);
  var mode = FileLock.EXCLUSIVE;
  var raf = file.openSync(mode: APPEND);
  try {
    raf.lockSync(mode);
    print('LOCK SUCCEEDED');
  } catch (e) {
    print('LOCK FAILED');
  } finally {
    raf.closeSync();
  }
}

lockSyncTest.dart file:

import "dart:async";
import "dart:io";

// Check whether the file is locked or not.
checkLock(String path, {bool locked}) {
  // Client process returns either 'LOCK FAILED' or 'LOCK SUCCEEDED'.
  var expected = locked ? 'LOCK FAILED' : 'LOCK SUCCEEDED';
  var arguments = []
  //  ..addAll(Platform.executableArguments)
    ..add(Platform.script.resolve('lockSyncTest_lib.dart').toFilePath())
    ..add(path);
  return Process
      .run(Platform.executable, arguments)
      .then((ProcessResult result) {
    if (result.exitCode != 0 || !result.stdout.contains(expected)) {
      print("Client failed, exit code ${result.exitCode}");
      print("  stdout:");
      print(result.stdout);
      print("  stderr:");
      print(result.stderr);
      print("  arguments:");
      print(arguments);
    }
  });
}

main() {
  int fLen = 10;
  File file = new File('/tmp/f1.txt');

  var rf = file.openSync(mode: FileMode.WRITE);
  rf.writeFromSync(new List.filled(fLen, 1));
  rf.lockSync(FileLock.EXCLUSIVE);

  file.readAsBytesSync();

  var tests = [
    () => checkLock(rf.path, locked: true),
  ];
  Future.forEach(tests, (f) => f()).whenComplete(() {
    rf.unlockSync();
    rf.closeSync();
    file.deleteSync();
  });
}
alexgoussev commented 4 years ago

It may be because of this: "On Linux and OS X this uses advisory locks, which have the surprising semantics that all locks associated with a given file are removed when any file descriptor for that file is closed by the process. Note that this does not actually lock the file for access. Also note that advisory locks are on a process level. This means that several isolates in the same process can obtain an exclusive lock on the same file." (A quote from https://api.dart.dev/dev/dart-io/RandomAccessFile/lock.html)