Skip to content

Conversation

notoriaga
Copy link
Contributor

@notoriaga notoriaga commented Jan 28, 2022

Based on the feedback here - https://swift-nav.atlassian.net/wiki/spaces/~460004640/pages/2108063854/FileIO+feedback

  • "Nested” help messages confusing/Current CLI usage of fileio is confusing
    • switched to the "scp style" commands for up/downloading like was recommended
  • Printing progress doesn’t seem to work on Windows (just suddenly appears as 100% done when finished)
    • uses an off the shelf progress bar (that supports windows). Also adds care of showing things like upload speed which is nice. Haven't actually tested it on windows yet
  • Error messages formatted as Rust errors not nice
    • the error shown is a special case for tcp connections where we might need to display multiple errors (one for each address we attempt to connect to). We were printing the vec with the debug representation, which is probably why it looked weird. I made a tweak to make the error display similarly to how anyhow displays error chains
  • list command seems to hang on Windows
    • I think not requiring the reader thread to be joined avoids this issue
➜  swift-toolbox git:(steve/fileio-cli) ✗ cargo fileio ./a.txt 10.1.54.1:/persistent/a.txt   
    Finished dev [unoptimized + debuginfo] target(s) in 0.08s
     Running `target/debug/fileio ./a.txt '10.1.54.1:/persistent/a.txt'`
Error: Could not connect to 10.1.54.1:55555
Caused by:
    connection timed out

progress

^ I changed the styling to be a bit more plain, and also added a spinner for reads (because we don't know the file size before hand). I don't really have an opinion on how either should look. It's pretty easy to mess around with if anyone is interested

@notoriaga notoriaga marked this pull request as draft January 28, 2022 01:41
@notoriaga notoriaga force-pushed the steve/fileio-cli branch 2 times, most recently from a56f544 to 687bb2c Compare January 30, 2022 01:04
@notoriaga notoriaga marked this pull request as ready for review January 30, 2022 01:31
@notoriaga notoriaga changed the title [wip] fileio cli fileio cli Jan 30, 2022
@notoriaga
Copy link
Contributor Author

I think reading might have a bug, appears to just hang sometimes

@notoriaga notoriaga changed the title fileio cli fileio cli improvments [DEVINFRA-602] [DEVINFRA-601] Jan 30, 2022

impl Remote {
fn connect(&self, conn: ConnectionOpts) -> Result<Fileio> {
let (reader, writer) = if self.host.parse::<SocketAddr>().is_ok() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure how well this will work, if it looks like a tcp addr then we try and connect to tcp, otherwise we assume it's serial.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this need to be self.host.parse::<IpAddr>().is_ok()? As the port is specified as a different argument? Not sure how this is working for you otherwise, unless I'm misunderstanding how to enter the CLI args?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yup good catch!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually how about

let (reader, writer) = if File::open(&self.host).is_ok() {
    SerialConnection::new(self.host.clone(), conn.baudrate, conn.flow_control)
        .try_connect(None)?
} else {
    TcpConnection::new(self.host.clone(), conn.port)?.try_connect(None)?
};

I think we should support using a hostname, and looking one up takes a bit of time so I think we should do it second. File::open(&self.host).is_ok() seems to work on windows for checking if something is a serial port, haven't tried linux yet

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds reasonable to me, would Path::exists be very slightly better to save an additional open?

Copy link
Contributor Author

@notoriaga notoriaga Jan 31, 2022

Choose a reason for hiding this comment

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

Tried that and for whatever reason Path::exists returns false for a com port on windows, but opening the file succeeds? I don't really understand windows that well, but might have something to do with it not having quite the same "everything is a file" approach that unix has

/// Piksi File IO operations.
#[derive(Parser)]
#[clap(
name = "fileio",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the context of the "Swift Toolbox" I think this name makes sense, but it also feels a little generic. Maybe piksi-fileio or something would be better

.into_remote()
.context("--delete flag requires <SRC> to be a remote target")?;
let fileio = remote.connect(conn)?;
fileio.remove(remote.path)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Over TCP, this doesn't work for me (the file doesn't get deleted) and, as far as I can tell, it's because the socket gets shut down too quickly. It does work when there's a short 1s sleep added (though I think much less than 1s would suffice as well). Comparing wireshark captures for the Python fileio and this version with a 1s delay, I can see:

To Piksi: PSH ACK
From Piksi: ACK
To Piksi: FIN ACK
From Piksi: FIN ACK
To Piksi: ACK

rust_with1sdelay.zip

But without the delay I see:

To Piksi: PSH ACK
To Piksi: FIN ACK
From Piksi: ACK
From Piksi: ACK
From Piksi: RST, ACK

rust.zip

I think SO_LINGER would help here but it looks like it's only enabled in nightly at the moment. The easy solution is probably just to add a delay here 🤷‍♂️ . I guess read/write should be fine as they wait for SBP layer acks before closing the connection.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch, added the sleep. https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.set_nodelay might also work, maybe the message never gets set because its not enough data. Regardless I kind of like the sleep, make it feel like the tool is waiting for a ack even though its not 😆

notoriaga and others added 3 commits January 30, 2022 16:39
- Show some example usages in help text

Co-authored-by: Steven Meyer <[email protected]>
Co-authored-by: notoriaga <[email protected]>
None => continue,
};
if elapsed < FILE_IO_TIMEOUT {
std::thread::sleep(FILE_IO_TIMEOUT - elapsed);
Copy link
Contributor Author

@notoriaga notoriaga Jan 31, 2022

Choose a reason for hiding this comment

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

There was sometimes a bit of a delay sometimes after finishing a write, which was because we were waiting for the timeout thread to join and it was asleep. This lets up wake up the timeout thread when we finish so we can exit faster

) {
let mut batch = Vec::with_capacity(config.batch_size);
let send_batch = move |batch: &mut Vec<MsgFileioWriteReq>| -> bool {
let mut guard = pending_map.lock();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This fixes a weird race condition (which I only seem to ran into reliably on windows) where we'd check to see if we finished writing by checking if pending_map was empty. The map would be empty because the request making thread didn't get a chance to insert the new requests. Holding the lock here seems to make it work

Copy link
Contributor Author

@notoriaga notoriaga Jan 31, 2022

Choose a reason for hiding this comment

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

This bug manifests as a write "hanging", I'm willing to bet this has affected things like updating firmware (again, mostly appears to have been a windows issue for whatever reason)

@notoriaga notoriaga requested review from a team and samvrlewis January 31, 2022 23:59
};
if elapsed < FILE_IO_TIMEOUT {
std::thread::sleep(FILE_IO_TIMEOUT - elapsed);
timeout_parker.park_timeout(FILE_IO_TIMEOUT - elapsed);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm seeing the upgrade process hang when connected to a device via serial but not using a tcp connection is there something we could do in this PR to address it? I do see this message as well if it is related: timeout thread finished. Somewhat unrelated but also appears to be struggling with the speed of serial, the time to load the settings. See:
https://swift-nav.atlassian.net/browse/CPP-641

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that with this pr? That may have been related to the other change with the lock

Copy link
Collaborator

@john-michaelburke john-michaelburke Feb 1, 2022

Choose a reason for hiding this comment

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

I think this issue is on main as well. I was just wondering if there was a timeout here you are touching that could possibly resolve the issue. I could understand addressing this in a separate PR too if it is more involved.

Copy link
Contributor

@samvrlewis samvrlewis left a comment

Choose a reason for hiding this comment

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

LGTM!

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.

4 participants