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

refactor: add common crates #1281

Merged
merged 5 commits into from
May 6, 2022
Merged

refactor: add common crates #1281

merged 5 commits into from
May 6, 2022

Conversation

ethowitz
Copy link
Contributor

@ethowitz ethowitz commented Apr 14, 2022

Description

  • Add the following crates:
    • Top-level syncstorage crate
    • syncstorage-db-common
    • syncstorage-common
    • tokenserver-common
  • Remove the following dependencies from the database code:
    • ApiError
    • Actix Web
    • HawkIdentifier
  • Make DbError.kind and ApiError.kind private to simplify API

Things I was unsure about:

  • I had to remove a lot of the #[cfg(test)] annotations, since anything pinned to the test feature isn't made public to other crates. I don't think this is a big deal but just wanted to mention it

Testing

No change in functionality

Issue(s)

Closes #1275

@ethowitz ethowitz requested a review from a team April 14, 2022 20:20
@ethowitz ethowitz changed the title refactor: add common crates NOT READY FOR REVIEW Apr 14, 2022
@ethowitz ethowitz marked this pull request as draft April 14, 2022 20:42
@ethowitz ethowitz removed the request for review from a team April 14, 2022 20:42
@ethowitz ethowitz force-pushed the refactor/add-common-crates branch 2 times, most recently from 59dc0e6 to 6018cf7 Compare April 15, 2022 17:51
@ethowitz
Copy link
Contributor Author

I made the opinionated decision to remove syncstorage-rs's dependency on Actix's web::block in favor of tokio's task::spawn_blocking. This prevents us from having to pull Actix in as a dependency for libraries that don't otherwise need it. I'm definitely open to reverting the change if the reviewer thinks it isn't worth it, but I'm trying to separate out the concerns of each of the new crates to reduce the cognitive complexity of how the pieces fit together.

@ethowitz ethowitz marked this pull request as ready for review April 15, 2022 17:53
@ethowitz ethowitz changed the title NOT READY FOR REVIEW refactor: add common crates Apr 15, 2022
@ethowitz ethowitz requested a review from a team April 15, 2022 17:54
@ethowitz ethowitz force-pushed the refactor/add-common-crates branch from 6018cf7 to 2db1c2f Compare April 25, 2022 20:47
@pjenvey
Copy link
Member

pjenvey commented Apr 29, 2022

  • I had to remove a lot of the #[cfg(test)] annotations, since anything pinned to the test feature isn't made public to other crates. I don't think this is a big deal but just wanted to mention it

FYI at one point the unit tests were in a separate crate (IIRC so they ran on nightly to utilize nightly only async/await 😄 ) and instead of wrapping things in cfg(test) we had a db_test feature they could opt into. I don't think it's worth doing this again though, the unit tests really belong with the syncstorage crate IMO.

I made the opinionated decision to remove syncstorage-rs's dependency on Actix's web::block in favor of tokio's task::spawn_blocking.

It looks like actix_web 4.0's block was changed from actix_threadpool to just be tokio's spawn_blocking underneath so we were going to end up with it anyway. So switching over is fine but with one caveat, that ACTIX_THREADPOOL env var we adjust in settings will no longer be relevant, so we should remove it.

I can't recall tokio spawn_blocking's typical thread pool size, we should double check what it will end up being for us. If it seems too small we can always just load test first and only worry about it if performance looks degraded.

@ethowitz
Copy link
Contributor Author

ethowitz commented May 2, 2022

Looks like the default upper limit on tokio's blocking threads is 512: https://docs.rs/tokio/latest/tokio/runtime/struct.Builder.html#method.max_blocking_threads

I think that should be plenty given that we currently set ACTIX_THREADPOOL to be max(num_cpus * 5, db_pool_max_size)

Copy link
Member

@pjenvey pjenvey left a comment

Choose a reason for hiding this comment

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

Just a couple small things.

Thanks for carefully doing this, I really appreciate the git history being preserved.

Comment on lines 138 to 139
.await
.map_err(ApiError::from)?;
Copy link
Member

Choose a reason for hiding this comment

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

Looks like this'll continue working:

Suggested change
.await
.map_err(ApiError::from)?;
.await?;

Comment on lines 140 to 141
.map_err(|_| TokenserverError::resource_unavailable())?
.map_err(Into::into)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.map_err(|_| TokenserverError::resource_unavailable())?
.map_err(Into::into)
.map_err(|_| TokenserverError::resource_unavailable())?

@@ -112,6 +117,17 @@ impl BatchBsoBody {
}
}

impl From<BatchBsoBody> for PostCollectionBso {
Copy link
Member

Choose a reason for hiding this comment

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

Leave this for now but I'll note we had a TODO comment somewhere that dissapeared to kill one of these types. I logged #1296 to revisit it later.

.map(|id| (id, "db error".to_owned())),
)
}
Err(e) if e.is_conflict() || e.is_quota() => return Err(e.into()),
Copy link
Member

Choose a reason for hiding this comment

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

🎉

@ethowitz ethowitz requested a review from pjenvey May 5, 2022 15:39
@ethowitz ethowitz force-pushed the refactor/add-common-crates branch from 8cb1814 to c7f1b7f Compare May 5, 2022 15:51
@ethowitz
Copy link
Contributor Author

ethowitz commented May 5, 2022

Thanks for the review @pjenvey -- this was a long one!

@ethowitz
Copy link
Contributor Author

ethowitz commented May 5, 2022

One thing I just thought of: I changed the database methods to return a DbError instead of an ApiError, and I think that makes the backtrace that gets reported as part of the final ApiError less granular, since the conversion to an ApiError happens in the handler, and it's the conversion from DbError to ApiError that triggers the backtrace collection. Should we add a backtrace to DbError to fix this?

@pjenvey
Copy link
Member

pjenvey commented May 5, 2022

Yea, good call.

Copy link
Member

@jrconlin jrconlin left a comment

Choose a reason for hiding this comment

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

Looks good!

I'm a little concerned about some of the test functions potentially "leaking" into non-test, since those tend to act without safety checks, but I'm fine with flagging them softly for later potential cleanup. Since they seem to be fairly isolated, perhaps we create a "test" trait we apply? 🤷🏻‍♂️

offset,
ids,
..
} = params.params;
let now = self.timestamp().as_i64();
Copy link
Member

Choose a reason for hiding this comment

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

Thank You!

(Sorry, but I kinda hated the source masking that this was doing.)

@@ -2128,13 +2104,11 @@ impl<'a> Db<'a> for SpannerDb {
}
}

#[cfg(test)]
fn create_collection(&self, name: String) -> DbFuture<'_, i32> {
Copy link
Member

Choose a reason for hiding this comment

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

My only thought about these functions is that they're really not supposed to be used outside of tests. I wonder if it might make sense to eventually move them into a test module rather than have them sprayed around like they currently are. (I also wonder if it might make sense to flag these as test helper functions, like with a comment or something.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I think it might be wise to do something with them. Putting them into a separate trait would at least make them slightly harder to use by mistake 🤔 I'll log an issue for this

@@ -91,6 +80,23 @@ pub struct PoolState {
pub idle_connections: u32,
}

impl From<diesel::r2d2::State> for PoolState {
Copy link
Member

Choose a reason for hiding this comment

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

🎉

Err(DbErrorKind::Integrity(
"Invalid modified i64 (< 0)".to_owned(),
))?;
return Err(DbErrorKind::Integrity("Invalid modified i64 (< 0)".to_owned()).into());
Copy link
Member

Choose a reason for hiding this comment

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

ugh, yeah, the previous version was clever. Thanks!

fn from(db_error: DbError) -> Self {
Self {
status: db_error.status,
backtrace: db_error.backtrace.clone(),
Copy link
Member

Choose a reason for hiding this comment

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

I won't hold up this PR any longer over this but we could avoid this clone -- maybe adding a backtrace2 method that defers to the inner DbError + making the ApiError::backtrace field a private Option<Backtrace>.

thiserror seems to provide a nice way of automatically implementing this for the std::Error::backtrace method but that method's still unstable, unfortunately making many backtrace things like this a bit clunky.

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 we could also use mem::take here, but I'm not sure if that's actually much better than clone (i.e. would memory be allocated for the newly-created default value?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The answer appears to be yes, as Backtrace::default() just calls Backtrace::new(), which just creates a backtrace :(

@ethowitz ethowitz merged commit a52900f into master May 6, 2022
@ethowitz ethowitz deleted the refactor/add-common-crates branch May 6, 2022 21:42
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.

Create *-common and syncstorage crates
3 participants