-
Notifications
You must be signed in to change notification settings - Fork 15
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
Add native bindings and API #30
Conversation
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.
looks good, but i have some questions and suggestions
e329dbb
to
151cd43
Compare
please fix conflict with client.go |
151cd43
to
46b3ca6
Compare
As I'm understand now its ready for merge? @noah8713 ? |
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 am still reviewing and submit the comments I have so far. Please also fold my comments from #28 if relevant.
In addition, each commit should be independently correct and tested. I'd suggest to squash the unit tests to the commits they belong to.
@hzhou8 why you prefer panic and not error? |
It depends on whether we are doing error handling or assertion. For my understanding panic is the way we do assertion in Go (Please correct me if I am wrong). In the above switch-case scenario it is determined by code in this library itself that the "default" branch is impossible, so "assertion" should be used instead of error handling. |
You right, but as i say panic is harder to catch and convert to structure log, so I'm prefer to avoid it. |
In this case you don't need to catch/convert. It is not about error handling. It just logically shouldn't happen. So if it happens we don't really want to do error handling, and assert/panic is for this situation. A more extreme example is: switch <a boolean var>: { In this example, the error return is completely unnecessary. In our case, the function nativeTypeFromExtended() doesn't need to return any error, which also saves the unnecessary burden for the caller to do error handling. Could you propose an alternative if panic is not preferred? |
In case of you extreme example - i can't =)
so from this point of view i'm prefer not have panic inside library code because you must specify for all methods that can be panic info about it. And users of the library must always use recovery to display some useful info about it. |
@vtolstov thanks for sharing your use case. Your concern is valid, but I think the assumption of "no panic inside library" is unrealistic. Even if library code doesn't call panic, it can still panic due to runtime errors such as "index out of range". Of course one can argue that the code should ensure "out of range" and other runtime error never happens. Well, this is true as long as we write the code correctly. I think same principle just applies to the context here - we should ensure nativeTypeFromExtended() handles all atomic types and ensuring the callers of it never pass in an undefined atomic type. This is pretty straightforwardly doable because they are all internal functions.
And now in fact I am surprised that we are in case 1), and I added a comment here: https://github.com/eBay/libovsdb/pull/30/files/7d3749a59bf564e0c452c754500aae683c64dccb#r600761873 With this comment addressed, we are in case 2), and we don't need to do error handling at: e235c30#diff-e29a67e14ba2eeb4cd617c06383912da10f348f70e1643c6189b2f1a20d02eb1R68 @amorenoz what do you think? |
fa7af2c
to
7671474
Compare
Signed-off-by: Adrian Moreno <[email protected]>
The way the column types are specified in RFC7047 is not directly unmarshallable by the json library. This patch adds the necessary structs and functions to manually unmarshal the schema definition. The result is the possibility of determining the exact native go type needed to store each column type. Several approaches were considering when implementing this: A) Multiple rounds of json.Unmarshal storing the partial in in-struct json.rawMessage B) Single call to json.Unmarshall and manually decoding the rest of the message (using reflex to guess the type of incoming data) C) Multiple rounds of json.Unmarshal storing partials in private temporary structs. After discarting A) for it's high memory consumption, B) and C) were compared: B) has lower memory allocation needs but more LOC C) has higher memory allocation needs (though after GC, it's the same or less than B), and fewer LOC. This patch implements C) as a good balance between maintainablity and memory efficiency. Signed-off-by: Adrian Moreno <[email protected]>
Signed-off-by: Adrian Moreno <[email protected]>
Parsing the schema many times has, of course, no practical sense other than be able to use a profiler to inspect memory and cpu consumption Signed-off-by: Adrian Moreno <[email protected]>
Add native <-> ovs format bindings based on schema In order to be able to translate ovsdb data to and from libovsdb format, we need to know the schema of the column. Without it we would not know which string to convert to UUID or what's the type of empty sets. Based on DatabaseSchema, we can infer the type of each column and make a deterministic translation bindings.go really offers two functions OvnToNative and NativeToOvn Signed-off-by: Adrian Moreno <[email protected]>
The Native API allows the user to interact with libovsdb.client without having to deal with libovsdb data types. Native types, slices and maps are used directly. Signed-off-by: Adrian Moreno <[email protected]>
Signed-off-by: Adrian Moreno <[email protected]>
Signed-off-by: Adrian Moreno <[email protected]>
Latest update (to help focus the reviews):
|
Thanks @amorenoz and all for the great work and reviews. |
@amorenoz thanks for great work! |
Following the idea described in #29, this PR tries to add schema-based support for native bindings in libovsdb.
Why is this desired?
OvsSet,
OvsMapand
OvsUUID`, to native golang types.Why schema-based?
How does the API look now?
For instance, when you get the
TableUpdates
, after performing the transformations of the Row, you still have amap[string] interface{}
. However, the client does not have to do any type assertions. If columnfoo
holds a list of uuids, you can safely cast itresult["foo"].([]string)
and use it. No more GoMap or GoSets either.An example of how to use it can be seen in the
examples/play_with_ovs
As another example, I have adapted go-ovn/logical_router.go to use this API here. It reduces ~50 LOC. Many more could be reduced if the rest of the library is updated and if the ovs->native translation is performed before adding the objects to the cache.
What's next?
Based on this PR, we can very easily add dynamic ORM-like API based on struct tags (PoC to come) as described in #29
Pushing this PR early on to get feedback on the approach and implementation.
It is based on #28