Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[native_assets_builder] Lock the build directory #1384

Merged
merged 17 commits into from
Aug 6, 2024
Merged

Conversation

dcharkes
Copy link
Collaborator

@dcharkes dcharkes commented Jul 31, 2024

This makes the native assets builder lock the build directories so that it can be invoked concurrently from multiple dart and flutter processes.

Closes: #1319

The implementation of the locking is in package:native_assets_cli/locking.dart contains runUnderDirectoryLock, so that we can reuse it for #1379. (#1379 Requires more changes though, it needs to also give users access to a shared directory via the BuildConfig.)

Copy link

github-actions bot commented Jul 31, 2024

PR Health

Breaking changes ✔️

Details
Package Change Current Version New Version Needed Version Looking good?
native_assets_cli Non-Breaking 0.7.3-wip 0.7.3-wip 0.7.3-wip ✔️

Changelog Entry ✔️

Details
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

API leaks ✔️

Details

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbols

License Headers ✔️

Details
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/ffigen/example/libclang-example/generated_bindings.dart
pkgs/ffigen/example/shared_bindings/generate.dart
pkgs/ffigen/example/shared_bindings/lib/generated/a_gen.dart
pkgs/ffigen/example/shared_bindings/lib/generated/a_shared_b_gen.dart
pkgs/ffigen/example/shared_bindings/lib/generated/base_gen.dart
pkgs/ffigen/example/simple/generated_bindings.dart
pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart
pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_symbol_address_collision_bindings.dart
pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_type_name_collision_bindings.dart
pkgs/ffigen/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_comment_markup_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_enum_int_mimic_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_forward_decl_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_imported_types_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_opaque_dependencies_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_packed_structs_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_regress_384_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_unions_bindings.dart
pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_varargs_bindings.dart
pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart
pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart
pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
pkgs/ffigen/test/native_test/_expected_native_test_bindings.dart
pkgs/jni/lib/src/lang/jcharacter.dart
pkgs/jni/lib/src/third_party/generated_bindings.dart
pkgs/jni/lib/src/third_party/global_env_extensions.dart
pkgs/jni/lib/src/third_party/jni_bindings_generated.dart
pkgs/jnigen/android_test_runner/lib/main.dart
pkgs/jnigen/example/in_app_java/lib/android_utils.dart
pkgs/jnigen/example/kotlin_plugin/example/lib/main.dart
pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart
pkgs/jnigen/example/kotlin_plugin/lib/kotlin_plugin.dart
pkgs/jnigen/example/pdfbox_plugin/lib/pdfbox_plugin.dart
pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart
pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart
pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/_package.dart
pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart
pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/_package.dart
pkgs/jnigen/lib/src/bindings/descriptor.dart
pkgs/jnigen/lib/src/elements/elements.g.dart
pkgs/jnigen/test/jackson_core_test/third_party/bindings/com/fasterxml/jackson/core/_package.dart
pkgs/jnigen/tool/command_runner.dart
pkgs/swift2objc/lib/src/config.dart
pkgs/swift2objc/lib/src/generate_wrapper.dart
pkgs/swift2objc/lib/src/generator/_core/utils.dart
pkgs/swift2objc/lib/src/generator/generator.dart
pkgs/swift2objc/lib/src/generator/generators/class_generator.dart
pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_property_declaration.dart
pkgs/swift2objc/lib/src/transformer/_core/unique_namer.dart
pkgs/swift2objc/lib/src/transformer/_core/utils.dart
pkgs/swift2objc/lib/src/transformer/transformers/transform_property.dart

Package publish validation ✔️

Details
Package Version Status
package:ffi 2.1.3-wip WIP (no publish necessary)
package:ffigen 14.0.0-wip WIP (no publish necessary)
package:jni 0.11.0-wip WIP (no publish necessary)
package:jnigen 0.10.0 already published at pub.dev
package:native_assets_cli 0.7.3-wip WIP (no publish necessary)
package:objective_c 1.1.0 already published at pub.dev
package:swift2objc 0.0.1-wip WIP (no publish necessary)
package:swiftgen 0.0.1-wip WIP (no publish necessary)

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@dcharkes
Copy link
Collaborator Author

@lrhn Could you please review Directory.exclusive. Does the implementation make sense? (I probably broke some variants? What about zones?)

@dcharkes
Copy link
Collaborator Author

@mkustermann @lrhn Any suggestions on how to address exclusivity within the Dart process? Within an isolate we can achieve this with a global variable. But within an isolate group we'd need dart:concurrent most likely. And in between isolate groups in the same Dart VM, I have no idea. Any suggestions? 🙂

@coveralls
Copy link

coveralls commented Jul 31, 2024

Coverage Status

coverage: 92.838% (+0.03%) from 92.81%
when pulling 9e00d13 on concurrency
into b0fdf4d on main.

pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
@lrhn
Copy link
Member

lrhn commented Jul 31, 2024

The zones are fine. Everything happens in the same zone where exclusive is called.

@dcharkes dcharkes requested a review from lrhn August 2, 2024 09:03
Copy link
Collaborator Author

@dcharkes dcharkes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mkustermann !

pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
pkgs/native_assets_builder/lib/src/utils/file.dart Outdated Show resolved Hide resolved
Copy link
Member

@mkustermann mkustermann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with comments

pkgs/native_assets_cli/lib/src/locking/locking.dart Outdated Show resolved Hide resolved
@dcharkes
Copy link
Collaborator Author

dcharkes commented Aug 6, 2024

Greatly appreciated @mkustermann !

@auto-submit auto-submit bot merged commit a5290f7 into main Aug 6, 2024
36 checks passed
@auto-submit auto-submit bot deleted the concurrency branch August 6, 2024 12:51
Logger? logger,
}) async {
const lockFileName = '.lock';
final lockFile = File.fromUri(directory.uri.resolve(lockFileName));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either use package:path, or make your own join function:

static File _fileInDir(Directory path, String filename) {
  var separator = Platform.pathSeparator;
  var dirPath = path.path;
  if (path.endsWith(separator)) separator = '';
  return File('$dirPath$separator$filename');
}

Creating a URI from a Directory path (including converting all platform path separators to / on Windows), do one resolve with a file name, and the converting that back to a file path, is far too much work for what it does.

It may be "easy to write" (you don't have to worry about using the right path separator, or having multiple of them), but it's introducing a concept (Uri) that has no place in the code. That makes the code more complicated than necessary.

);
printed = true;
}
await Future<void>.delayed(const Duration(milliseconds: 50));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this wait?
There's probably a good reason. Document it and why the magic number was chosen.

If I understand it, it's just a delay before retrying. Reasonable to have one. Is 50 ms a little short? Or long? (I don't know! Depends on why it could fail to get the lock, rather than just block until it has the lock. If there is no timeout, could we use a blocking async lock, if one exists?)

Logger? logger,
}) async {
if (!await file.exists()) await file.create(recursive: true);
final randomAccessFile = await file.open(mode: FileMode.write);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Windows does not allow another file descriptor to write to a locked file, and FileMode.write says "The file is overwritten if it already exists. The file is created if it does not already exist.", shouldn't this fail if the file is already locked? At least on Windows?

(If not, why not?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is covered by multiple tests. They explicitly lock the file, and then spawn a new process that executes exactly this code. I believe opening the file in write mode (which gives you a file handle) is fine. It's the write operation with such file handle that will fail. (You need a file handle to do the locking call to begin with, so it would be weird if getting the file handle would fail.)

HosseinYousefi pushed a commit that referenced this pull request Aug 19, 2024
This makes the native assets builder lock the build directories so that it can be invoked concurrently from multiple `dart` and `flutter` processes.

Closes: #1319

The implementation of the locking is in `package:native_assets_cli/locking.dart` contains `runUnderDirectoryLock`, so that we can reuse it for #1379. (#1379 Requires more changes though, it needs to also give users access to a shared directory via the `BuildConfig`.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[native_assets_builder] Concurrent execution of NativeAssetsBuilder
4 participants