Skip to content

Conversation

notoriaga
Copy link
Contributor

No description provided.


#[derive(Clap, Debug)]
#[clap(about = "Cli subcommands.")]
pub enum CliCommand {
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 this is the best way to add utility binaries to the console. It would be nice if we could emulate what the current console has with a bunch of different entry points depending on what you are doing

Copy link
Collaborator

Choose a reason for hiding this comment

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

Based on your concern would it make more sense to have a separate bin/crate for fileio and us import the fileio stuctopt and here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think a separate bin makes sense. I guess right now there is no rust binary correct? We could add a console_pp/console_backend/src/bin directory and put utils there (specifically utils that don't need to launch the frontend). It wouldn't have to actually be a separate crate, because you can have multiple binaries per crate

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

@notoriaga notoriaga requested review from jayvdb, john-michaelburke and silverjam and removed request for john-michaelburke and silverjam June 14, 2021 19:35
@notoriaga notoriaga force-pushed the steve/fileio-next branch from 263d641 to 6bf7bdd Compare June 15, 2021 01:58
@notoriaga notoriaga force-pushed the steve/fileio-next branch from 94344a7 to 7d97f41 Compare June 15, 2021 02:35
@john-michaelburke
Copy link
Collaborator

john-michaelburke commented Jun 15, 2021

@notoriaga To fix your benchmark issue I think you need to add open subcommand here:
https://github.com/swift-nav/console_pp/blob/234174a861eba53851b2a6b72b7e1fcc1fdf3929/utils/bench_runner.py#L115

@notoriaga
Copy link
Contributor Author

@notoriaga To fix your benchmark issue I think you need to add open subcommand here:

https://github.com/swift-nav/console_pp/blob/234174a861eba53851b2a6b72b7e1fcc1fdf3929/utils/bench_runner.py#L115

Hmm I ended up removing the sub command when I broke the io stuff out into it's own tool. Was able to get the benches running locally - it seems like occasionally the window doesn't close when running cargo make frontend-mem-bench which might be the cause of the timeout

@john-michaelburke
Copy link
Collaborator

@notoriaga To fix your benchmark issue I think you need to add open subcommand here:
https://github.com/swift-nav/console_pp/blob/234174a861eba53851b2a6b72b7e1fcc1fdf3929/utils/bench_runner.py#L115

Hmm I ended up removing the sub command when I broke the io stuff out into it's own tool. Was able to get the benches running locally - it seems like occasionally the window doesn't close when running cargo make frontend-mem-bench which might be the cause of the timeout

Yes from what I'm seeing the file is not opening properly on mac now from cli. I was also able to validate it works running on my linux VM. I also am able to open the file on mac through the GUI. Something is problematic with the cli.

shared_state.update_file_history(filename);
self.connect(conn, client_send.clone(), shared_state, RealtimeDelay::On);
if close_when_done {
close_frontend(&mut client_send);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe the self.connect is starting up the thread and immediately returning, then this check to see "close_when_done" executes so you probably need to move this logic into the thread.

Copy link
Contributor

Choose a reason for hiding this comment

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

🎉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Success! thanks @john-michaelburke

@notoriaga notoriaga force-pushed the steve/fileio-next branch from b46378e to 613e0ea Compare June 16, 2021 20:14
) -> Result<()> {
let conn = Connection::serial(device, baudrate, flow)?;
info!("Connected to serialport!");
// serial port history?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think saving the serial device history is a great idea because it depends on availability. I think having history of the port used or hardware/software flow could work but we can leave it for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh makes sense, removed the comment

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a future task in jira for this?
Local devices should have identifiers that can be used to filter out other types of connected devices, so the user can be shown only a list of connected swift-nav devices.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What I meant by depends on availability is that we refresh the device list for serial devices in order to populate which serial devices can be selected. A device previously connected to could not be available for various reasons, maybe a concession would be to at least remember the most recently connected to device and bump it to the top of the list if available. Also I think filtering out non swift devices is a great idea.

I added a couple jiras to log these.
Serial "swift-nav" device filter: https://swift-nav.atlassian.net/browse/CPP-229
Serial/port/flow history: https://swift-nav.atlassian.net/browse/CPP-230

}

pub fn write(&mut self, filename: String, data: impl Read) -> Result<()> {
self.remove(filename.clone())?;
Copy link
Contributor

Choose a reason for hiding this comment

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

should we try to keep the file, i.e. rename it, and only remove it after the write was successful ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

While I think that's a good idea, not sure the best way to handle it. afaik there is no sbp fileio message for renaming files

Copy link
Contributor

Choose a reason for hiding this comment

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

Oops yeah, didn't realize this was removing the file remotely

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this should be the current behavior of the console, in piksi_tools the write method has a trunc param which defaults to true and never seems to be overridden anywhere

Copy link
Contributor

Choose a reason for hiding this comment

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

afaik there is no sbp fileio message for renaming files

Surely there is some atomic operation available on the remote end to support overwriting files without the files being deleted first. If not, one needs to be added to the API.

Perhaps the overwrite occurs atomically only when all chunks have been received? In which case a .remove/trunc before sending the chunks is redundant.

If there is no way to overwrite without first deleting, IMO that non-atomacity should be exposed to the user. i.e. if the file already exists, confirm that the user wish to "first delete the remote file and then upload the new file". And the functions in this module need to clearly described what they are doing, in which case a new destroy_then_write function is needed to do this .remove() followed by the write, as that is in fact performing two distinct steps and the caller needs to know that this function should never be called on a file which is critical for the operation of the device.

Copy link
Contributor

@silverjam silverjam Jun 19, 2021

Choose a reason for hiding this comment

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

@jayvdb

The SBP FileIO API is certainly a bit janky, and we obviously can't change the behavior of old device firmware so improvements here would need to be a new set of SBP messages, or a new mode for the existing messages. Already there's a MSG_FILEIO_CONFIG_REQ message which enables the new "windowed transfer" approach, and if this message isn't ACK'd we need to fall back to the old sequential send/ACK transfer method (otherwise transfers with old devices and firmware versions would fail).

In general, I think there's a number of factors contributing to the oddness of this remove+write sequence:

  • the "ACK" (write response} packets have a request ID that only serves to signal that a write was received and presumably completed successfully, there's no requirements on the order or value of request IDs
  • the SBP write request includes an offset, so the writing daemon re-opens the file each time, seeks to the offset, then writes the bytes in the packet (this is what it used to do, the current daemon caches open file descriptors, but it has facilities for knowing when to flush the cache) for reference see: https://github.com/swift-nav/piksi_apps/blob/master/app/sbp_fileio_daemon/sbp_fileio.c#L1191
  • because of the above, we don't know if a file already exists at the location provided in the write message, since we don't have a "truncate" message, we just issue a remove to make sure that we don't end up corrupting the file upload (if for example the uploaded file ends up being shorter than the existing file)

So TL;DR... I agree this violates the "principle of least surprise" and we should just call this destroy_then_write or remove_then_write (or perhaps just overwrite?) to make it clear what's happening, and perhaps include some explanation on the doc string of the function. I don't think near term (or even long term) it's going to be feasible to make these write message more sane.


impl WriteState {
fn new(filename: String) -> Self {
let (chunk_size, filename) = if filename.ends_with('\x00') {
Copy link
Contributor

Choose a reason for hiding this comment

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

where are filenames with trailing nul coming from?

Or if these filenames are typically containing a trailing nul, why are there also cases of the filename not containing them. My guess is that this is allowing the filename to be provided from both local (no nul) and remote (with nul) sources, and this doesn't feel like the best way to handle two different data types.

Is there a significant penalty for removing the nul earlier and then re-adding the nul when building the SbpString?

As this is all internal to this module, I don't mind this being here, but I worry that the filename isnt being cleaned when it is first encountered, and that this may lead to bugs not being noticed in the future (i.e. by someone elses new code) when one datatype of filename is unintentionally used in the wrong context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My guess is that this is allowing the filename to be provided from both local (no nul) and remote (with nul) sources, and this doesn't feel like the best way to handle two different data types.

Yeah that's sort of what I was going for but in reality I don't this it will matter because, for example, when we list files with this module the trailing nuls are removed. so all inputs should not have the trailing nul even if they come from the remote device.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm wondering if SbpString are always null terminated, or if it's just for this usecase. Because if they are would could probably handle adding the nul terminators in the SbpString constructor - maybe @silverjam knows?

Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately libsbp has quite a lot of string encodings, @woodfell has a good write-up of the various encodings we use here: https://swift-nav.atlassian.net/wiki/spaces/~61688916/pages/1722942301/Design+Doc+-+libsbp#Strings

Once libsbp C API improvements are merged we'll have more metadata to work with, for reference see:

This adds a new encoding: ... field for string members of messages, and we'll be able to use this to make SbpString behave smarter.

Copy link
Contributor

Choose a reason for hiding this comment

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

In this case we need the null termination to form the write message appropriately, which looks something like <filename>\x00<file-data> on the wire. For this particular case I don't think we need the first if check since all the filenames should be coming from local sources, but we could add an assert and see if it ever fires.

@notoriaga notoriaga force-pushed the steve/fileio-next branch from 27ee004 to 1d2fa6b Compare June 18, 2021 18:00
@notoriaga notoriaga force-pushed the steve/fileio-next branch from 1d2fa6b to 99ef0b6 Compare June 18, 2021 18:06
@notoriaga notoriaga merged commit eb1cd18 into main Jun 21, 2021
@notoriaga notoriaga deleted the steve/fileio-next branch June 21, 2021 20:03
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