-
Notifications
You must be signed in to change notification settings - Fork 660
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
Landmark Routing 1 PR: Add primary key for landmark database and landmark getter via primary key #4224
Conversation
src/mjolnir/landmark_builder.cc
Outdated
ret = sqlite3_prepare_v2(db, select, strlen(select), &bounding_box_stmt, NULL); | ||
if (ret != SQLITE_OK) { | ||
throw std::runtime_error("Sqlite prepared select statement error: " + | ||
std::string(sqlite3_errmsg(db))); | ||
} | ||
|
||
// prep the landmark getter statement | ||
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id = ?"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for clarity I'd rename get_landmark
to get_landmark_by_id
and everything bbox related to get_landmarks_by_bbox
(note the plural).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you meant the function name below in this case not the prepared statement right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both but primarily the (public) function name, right. the prepare statement and variable names could/should be changed similarly, but that's more of a nit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we decided we wanted batching we'd either have to not use a prepared statement OR use one with a set level of batching. the latter would be like:
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id = ?"; | |
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
or maybe even programatically adding more question marks, and then when we fill them out in the query below we'd need to just repeat the last one until we've filled up all the question marks. if the batch size the person gave us in the vector was too small. and do more than 1 batch if the batch size the person gave us in the vector was too large
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added get_landmarks_by_ids
to flexibly fetch multiple landmarks by ids. the statement is not prepared in advance anymore and no min/max limit of landmark number is set. maybe we should set a max number?
src/mjolnir/landmark_builder.cc
Outdated
int landmark_type = -1; | ||
if (sqlite3_column_type(get_landmark_stmt, 2) != SQLITE_NULL) { | ||
landmark_type = sqlite3_column_int(get_landmark_stmt, 2); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can't happen can it? if so, we should throw I think. passing on a value of -1
would do crazy things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree, i think we can just skip the if completely and set the type without checking null. we dont ever put a null entry in the db so we cant ever get a null entry out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it
src/mjolnir/landmark_builder.cc
Outdated
if (sqlite3_column_type(bounding_box_stmt, 2) != SQLITE_NULL) { | ||
landmark_type = sqlite3_column_int(bounding_box_stmt, 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment holds here, type can't be optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some nits:)
src/mjolnir/landmark_builder.cc
Outdated
@@ -202,17 +245,18 @@ std::vector<Landmark> LandmarkDatabase::get_landmarks_in_bounding_box(const doub | |||
|
|||
int ret = sqlite3_step(bounding_box_stmt); | |||
while (ret == SQLITE_ROW) { | |||
const char* name = reinterpret_cast<const char*>(sqlite3_column_text(bounding_box_stmt, 0)); | |||
uint32_t landmark_id = static_cast<uint32_t>(sqlite3_column_int(bounding_box_stmt, 0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint32_t landmark_id = static_cast<uint32_t>(sqlite3_column_int(bounding_box_stmt, 0)); | |
auto landmark_id = static_cast<int64_t>(sqlite3_column_int64(bounding_box_stmt, 0)); |
valhalla/mjolnir/landmark_builder.h
Outdated
@@ -60,7 +60,7 @@ enum class LandmarkType : uint8_t { | |||
casino = 18, | |||
}; | |||
|
|||
using Landmark = std::tuple<std::string, LandmarkType, double, double>; | |||
using Landmark = std::tuple<uint32_t, std::string, LandmarkType, double, double>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using Landmark = std::tuple<uint32_t, std::string, LandmarkType, double, double>; | |
using Landmark = std::tuple<int64_t, std::string, LandmarkType, double, double>; |
valhalla/mjolnir/landmark_builder.h
Outdated
std::vector<Landmark> get_landmarks_in_bounding_box(const double minLat, | ||
const double minLong, | ||
const double maxLat, | ||
const double maxLong); | ||
|
||
Landmark get_landmark(const uint32_t pkey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Landmark get_landmark(const uint32_t pkey); | |
Landmark get_landmark(const int64_t pkey); |
src/mjolnir/landmark_builder.cc
Outdated
@@ -183,6 +194,38 @@ void LandmarkDatabase::insert_landmark(const std::string& name, | |||
pimpl->vacuum_analyze = true; | |||
} | |||
|
|||
Landmark LandmarkDatabase::get_landmark(const uint32_t pkey) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wonder if we should allow batching, this could improve efficiency when we are fetching these things:
Landmark LandmarkDatabase::get_landmark(const uint32_t pkey) { | |
std::vector<Landmark> LandmarkDatabase::get_landmark(const std::vector<int64_t>& pkeys) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea. maybe we should allow both cases
src/mjolnir/landmark_builder.cc
Outdated
if (i > 0) { | ||
sql += ", "; | ||
} | ||
sql += "?"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can put the actual value here instead of ?
and omit preparing the statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. but i notice sqlite officially suggests to use preparing statement when query includes variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely because they’re doing some internal validation of the variable type or so. I think in our use case here it’s fine to do as it is now, it’s not a multi-variable statement, just the same many times.
src/mjolnir/landmark_builder.cc
Outdated
const double maxLong) { | ||
// get multiple landmarks by their ids | ||
std::vector<Landmark> LandmarkDatabase::get_landmarks_by_ids(const std::vector<int64_t>& pkeys) { | ||
sqlite3_stmt* get_landmarks_by_ids_stmt = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should put a TODO to test how this performs and see if we should prepare a default query (like 10-20 elements) and if more come in we extend the statement preparation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -60,7 +60,7 @@ enum class LandmarkType : uint8_t { | |||
casino = 18, | |||
}; | |||
|
|||
using Landmark = std::tuple<std::string, LandmarkType, double, double>; | |||
using Landmark = std::tuple<int64_t, std::string, LandmarkType, double, double>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm I just realized this: not that we really need it but why not uint64_t for the index?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because the primary key has to be a signed 64 bit integer to get a free index on that column in sqlite. why they picked signed i do not know but if we want to use unsigned that means we have to add our own index. anyway this is what i read on the internet. if we were going to do something like that we should forget the primary key and use the osmid directly and add an index manually (this could be useful for debugging at some point?) but i figured at the moment its not needed, it did cross my mind though!
valhalla/mjolnir/landmark_builder.h
Outdated
* database connection is read-only or read-write. | ||
* @param db_name The file path of the SQLite database to connect to. | ||
* @param read_only Set to true to open the database in read-only mode, false for read-write. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nitpicky but we typically do this extra white space:
* database connection is read-only or read-write. | |
* @param db_name The file path of the SQLite database to connect to. | |
* @param read_only Set to true to open the database in read-only mode, false for read-write. | |
* database connection is read-only or read-write. | |
* | |
* @param db_name The file path of the SQLite database to connect to. | |
* @param read_only Set to true to open the database in read-only mode, false for read-write. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@nilsnolde are you good with the changes? anything else needed here? |
oops @nilsnolde @kevinkreiser I add a new commit to add extra space in docstrings after your approvals. can either of you review again? :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢
Issue
To faciliate landmark storage in tiles, primary key is added in landmark databse to enable getting a landmark via its primary key.
Tasklist
Requirements / Relations
Landmark Routing 3: Tile Storage of Associated Landmarks