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

Adds CodeCache handler #402

Merged
merged 8 commits into from
Jul 29, 2018
Merged

Adds CodeCache handler #402

merged 8 commits into from
Jul 29, 2018

Conversation

ry
Copy link
Member

@ry ry commented Jul 24, 2018

Depends on #396

@ry ry force-pushed the code_cache branch 2 times, most recently from b4ef3fb to 10ded40 Compare July 24, 2018 17:04
@@ -0,0 +1,47 @@
import("//build_extra/rust/rust.gni")

# TODO(ry) "flatbuffer.gni" should be "flatbuffers.gni" we should be consistant
Copy link
Member

Choose a reason for hiding this comment

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

Consistent

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

"--rust",

#"--gen-mutable",
#"--keep-prefix",
Copy link
Member

Choose a reason for hiding this comment

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

Why are these commented out?

src/deno_dir.rs Outdated
// https://github.com/ry/deno/blob/golang/deno_dir.go#L99-L111
pub fn setup() -> std::io::Result<()> {
// Only setup once.
if unsafe { ROOT != None } {
Copy link
Member

Choose a reason for hiding this comment

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

Why unsafe?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it's a static global.

src/binding.cc Outdated
v8::Uint8Array::New(ab, buf.data_ptr - buf.alloc_ptr, buf.data_len);
return view;
if (buf.alloc_ptr == nullptr) {
// If alloc_ptr isn't set, we memcpy.
Copy link
Member

Choose a reason for hiding this comment

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

This is alright.

src/deno_dir.rs Outdated
// In the Go code this was called SrcDir. Renaming to Deps.
// Example: /Users/rld/.deno/deps/
Deps,
// In the Go code this was called CacheDir. Renaming to GEN.
Copy link
Member

Choose a reason for hiding this comment

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

Gen or GEN ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

src/deno_dir.rs Outdated
}
pub use self::Dirname::*;

pub fn path(dirname: Dirname) -> &'static Path {
Copy link
Member

Choose a reason for hiding this comment

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

Using Path now, that's a step forward :)

src/deno_dir.rs Outdated
if unsafe { ROOT != None } {
return Ok(());
}
let home_dir = std::env::home_dir().expect("Could not get home directory.");
Copy link
Member

Choose a reason for hiding this comment

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

Would rather convert home_dir Path/PathBuf here and get rid of the unsafe block below.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is a PathBuf here already https://doc.rust-lang.org/std/env/fn.home_dir.html

The unsafe is for the static global assignment.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I didn't know this was considered unsafe

src/deno_dir.rs Outdated

// https://github.com/ry/deno/blob/golang/deno_dir.go#L32-L35
pub fn cache_path(filename: &str, source_code: &str) -> PathBuf {
let cache_key = source_code_hash(filename, source_code);
Copy link
Member

Choose a reason for hiding this comment

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

So if a file's dependencies change, there's no need to recompile?
(Just asking, I don't know)

Copy link
Member Author

Choose a reason for hiding this comment

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

That's right. In the compiled code the requires will reference the original module specifier, not the specifier of the compiled file.

Copy link
Member

Choose a reason for hiding this comment

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

What I mean is, some file might need to be recompiled if it's dependencies change. Like in C++ when a header changes.
I'n typescript this may be the case too but maybe not, idk. Did you consider this?

Copy link
Member Author

Choose a reason for hiding this comment

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

@piscisaureus Yeah, I don't think that happens... but let's see if we find any examples as we flesh out the tests.

pub fn read_file_sync(path: &Path) -> std::io::Result<String> {
File::open(path).and_then(|mut f| {
let mut contents = String::new();
f.read_to_string(&mut contents)?;
Copy link
Member

Choose a reason for hiding this comment

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

This is not generally safe, because a file's contents are not necessarily valid utf-8.
We'll make it read to a buffer later? Otherwise consider renaming the function to read_text_file_sync.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh - I thought Strings were like std::string. Sigh. Will change...

Copy link
Member

Choose a reason for hiding this comment

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

This gonna stay as it is?

src/handlers.rs Outdated
fn string_from_ptr(ptr: *const c_char) -> String {
let cstr = unsafe { CStr::from_ptr(ptr as *const i8) };
String::from(cstr.to_str().unwrap())
// Help. Is there a way to do this without macros?
Copy link
Member

Choose a reason for hiding this comment

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

I don't think so -- an &str expects to store a reference to it's underlying String, but *const c_char isn't and can't be used as such (a String is not just a pointer, but also stores length, capacity, refcount etc.).
This is the reason you have to construct a new String here.
If you make str_from_ptr a function then the String goes out of scope at the end of the function.
(you could also return both, but I suspect that might also defeat the purpose of this convenience wrapper).

@piscisaureus
Copy link
Member

Mostly LGTM now. Strangely I didn manage to build this PR, but now that I'm trying again, I get this error (freshly checked out, cleaned, third_party reset and cleaned etc).

C:\Users\BertBelder\d\deno>python tools\build.py
C:\Users\BertBelder\d\deno\third_party\depot_tools\gn gen C:\Users\BertBelder\d\deno\out\debug
Traceback (most recent call last):
File "C:/Users/BertBelder/d/deno/build/vs_toolchain.py", line 16, in
from gn_helpers import ToGNString
ImportError: No module named gn_helpers
ERROR at //build/config/win/visual_studio_version.gni:27:7: Script returned non-zero exit code.
exec_script("../../vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
^----------
Current dir: C:/Users/BertBelder/d/deno/out/debug/
Command: C:/Python27/python.exe -- C:/Users/BertBelder/d/deno/build/vs_toolchain.py get_toolchain_dir
Returned 1.
See //build/toolchain/win/BUILD.gn:8:1: whence it was imported.
import("//build/config/win/visual_studio_version.gni")
^----------------------------------------------------
See //BUILD.gn:9:1: which caused the file to be included.
group("all") {

@piscisaureus
Copy link
Member

Hmm, it seems that git creates the wrong kind of symlinks now that third_party has become a separate repo.

@robbym
Copy link
Contributor

robbym commented Jul 26, 2018

Are the global mutables necessary? Can't all of this go into a struct that owns those globals and methods?

@ry
Copy link
Member Author

ry commented Jul 26, 2018

@robbym I agree it shouldn't be global. I've reworked it to be a standalone struct.

@ry ry force-pushed the code_cache branch 2 times, most recently from 8c27dcc to 5bf369b Compare July 26, 2018 17:34
@ry
Copy link
Member Author

ry commented Jul 26, 2018

@piscisaureus PTAL. I've done some refactoring and added more tests.

  1. DenoDir is now a standalone struct - instead of using global variables. This makes threaded testing possible and is also the right thing to do.
  2. In order to store the DenoDir in the Deno struct and then retrieve it later, I've added from_c and deno_get_data.
  3. Due to that remove_dir_all, you may find you don't have all the deps for windows. I didn't want to inadvertently add unused stuff.. so I'll leave it to you to add winapi, if it is needed.

This does indeed give us 10x startup on a warm run:

~/src/deno> rm -rf ~/.deno/
~/src/deno> time ./out/release/deno tests/002_hello.ts
Hello World

real	0m0.615s
user	0m0.965s
sys	0m0.066s
~/src/deno> time ./out/release/deno tests/002_hello.ts
Hello World

real	0m0.074s
user	0m0.036s
sys	0m0.032s
~/src/deno>

@ry ry force-pushed the code_cache branch 3 times, most recently from 148cc38 to 6e47cfc Compare July 26, 2018 22:01
@piscisaureus piscisaureus mentioned this pull request Jul 28, 2018
@piscisaureus
Copy link
Member

piscisaureus commented Jul 28, 2018

The test fails for me:

output running 9 tests test deno_dir::test_resolve_module ... ok test deno_dir::test_cache_path ... ok test deno_dir::test_source_code_hash ... ok test deno_dir::test_code_cache ... ok test deno_dir::test_src_file_to_url ... ok test test_parse_core_args_1 ... ok test test_parse_core_args_2 ... ok test test_c_to_rust ... ok test deno_dir::test_code_fetch ... FAILED

failures:

---- deno_dir::test_code_fetch stdout ----
thread 'deno_dir::test_code_fetch' panicked at 'called Result::unwrap() on an Err value: ()', libcore\result.rs:945:5
note: Some details are omitted, run with RUST_BACKTRACE=full for a verbose backtrace.
stack backtrace:
0: std::sys::windows::backtrace::unwind_backtrace
at C:\projects\rust\src\libstd\sys\windows\backtrace\mod.rs:65
1: std::sys_common::backtrace::print
at C:\projects\rust\src\libstd\sys_common\backtrace.rs:59
2: std::panicking::default_hook::{{closure}}
at C:\projects\rust\src\libstd\panicking.rs:211
3: std::panicking::default_hook
at C:\projects\rust\src\libstd\panicking.rs:221
4: std::panicking::rust_panic_with_hook
at C:\projects\rust\src\libstd\panicking.rs:463
5: std::panicking::begin_panic_fmt
at C:\projects\rust\src\libstd\panicking.rs:350
6: std::panicking::rust_begin_panic
at C:\projects\rust\src\libstd\panicking.rs:328
7: core::panicking::panic_fmt
at C:\projects\rust\src\libcore\panicking.rs:71
8: core::result::unwrap_failed<()>
at C:\projects\rust\src\libcore\macros.rs:26
9: core::result::Result<url::Url, ()>::unwrapurl::Url,()
at C:\projects\rust\src\libcore\result.rs:782
10: test_rs_bin::deno_dir::DenoDir::resolve_module
at .\src\deno_dir.rs:169
11: test_rs_bin::deno_dir::DenoDir::code_fetch
at .\src\deno_dir.rs:98
12: test_rs_bin::deno_dir::test_code_fetch
at .\src\deno_dir.rs:273
13: test_rs_bin::__test::TESTS::{{closure}}
at .\src\deno_dir.rs:264
14: core::ops::function::FnOnce::call_once<closure,()>
at C:\projects\rust\src\libcore\ops\function.rs:223
15: alloc::boxed::{{impl}}::call_box<(),closure>
at C:\projects\rust\src\liballoc\boxed.rs:638
16: panic_unwind::__rust_maybe_catch_panic
at C:\projects\rust\src\libpanic_unwind\lib.rs:105

failures:
deno_dir::test_code_fetch

test result: FAILED. 8 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

The issue is that Url::from_file_path(&containing_file).unwrap(); panics if containing_file isn't an absolute path, and /baddir/badfile.ts isn't absolute on my system.

@ry
Copy link
Member Author

ry commented Jul 28, 2018

@piscisaureus I believe I've fixed that using your add_root! macro.

Copy link
Member

@piscisaureus piscisaureus left a comment

Choose a reason for hiding this comment

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

Your last patch makes the tests pass on windows.
The startup time numbers are really encouraging. Nice work!

I wonder what the "fix logger" commit fixes - I never had any trouble with it?

I had a few comments. See what you wanna do with them, lgtm otherwise.

src/deno_dir.rs Outdated
if cache_path.exists() {
Ok(())
} else {
let mut file = File::create(cache_path)?;
Copy link
Member

Choose a reason for hiding this comment

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

This is a race condition w.r.t to exists() -- probably should create the file in exclusive mode.
I also worry what might happen is there are two processes and one reads the cache file while the other is in the midst of writing it.
Not suggesting you fix it as part of this PR, but it'll have to be done some time.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a todo comment.

pub fn read_file_sync(path: &Path) -> std::io::Result<String> {
File::open(path).and_then(|mut f| {
let mut contents = String::new();
f.read_to_string(&mut contents)?;
Copy link
Member

Choose a reason for hiding this comment

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

This gonna stay as it is?

let errmsg = format!("{}", err);
reply_error(d, cmd_id, &errmsg);
}
// null response indicates success.
Copy link
Member

Choose a reason for hiding this comment

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

Implicit null response is a foot gun. Probably better to explicitly say reply_null() if a handler succeeds without a return value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree. I think this whole interface is going to change dramatically soon. This is just a first pass. I'll leave it as is now.

ptr: 0 as *const binding::DenoC,
dir: deno_dir::DenoDir::new(None).unwrap(),
});
let deno: &'a mut Deno = Box::leak(deno_box);
Copy link
Member

Choose a reason for hiding this comment

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

Jeez... I can see how this makes for some sleepless nights.
Why is Deno made mutable here if it gets cast to *const one line below?
(Not saying it's wrong, I just don't understand this very well.)

A little comment on what's going on here would be in order too (as in -- mention that C-Deno needs a reference to Rust-Deno. And why this leak is necessary (is it really btw?).

Copy link
Member Author

Choose a reason for hiding this comment

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

It gets returned as mut (but my confidence that this is optimal code is low)

@ry ry merged commit 604a8a6 into master Jul 29, 2018
@ry ry deleted the code_cache branch July 29, 2018 04:22
piscisaureus pushed a commit to piscisaureus/deno that referenced this pull request Oct 7, 2019
piscisaureus added a commit to piscisaureus/deno that referenced this pull request Jun 5, 2020
They finally tagged v2.0.0 so there's no reason to use our own fork any
longer.
piscisaureus added a commit to piscisaureus/deno that referenced this pull request Jun 5, 2020
hardfist pushed a commit to hardfist/deno that referenced this pull request Aug 7, 2024
…enoland#443)

A little cleanup and showcase how to wire up custom
module types in the `fs_module_loader.rs` example.

Ref denoland#402
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants