-
-
Notifications
You must be signed in to change notification settings - Fork 45
Adds support for last_sync attribute for Indexed Fixtures #2085
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
Conversation
last_sync attribute for Indexed Fixtures|
Hi Shubham, It seems a bit limiting for us to only be able to store a single attribute on the base element. A lot of the dispatch downstream seems quite complex: https://github.com/dimagi/commcare-core/pull/842/files#diff-de4be0557361343fe019d6c9b25d8598R111 I'm wondering whether it would make more sense to instead serialize and store a single TreeElement which contains all of the core attributes. That element could be deserialized in whole, and then all of the attribute dispath methods in the element https://github.com/dimagi/commcare-core/pull/842/files#diff-de4be0557361343fe019d6c9b25d8598R95 could just be forwarded along, IE that would allow us to basically keep track of whatever other details need to be added in the future as well |
|
@ctsims This is ready to be reviewed again. |
app/src/org/commcare/models/database/user/UserDatabaseUpgrader.java
Outdated
Show resolved
Hide resolved
app/src/org/commcare/models/database/IndexedFixturePathUtils.java
Outdated
Show resolved
Hide resolved
| TreeElement attrsHolder = null; | ||
| byte[] attrsBlob = c.getBlob(c.getColumnIndexOrThrow(INDEXED_FIXTURE_PATHS_COL_ATTRIBUTES)); | ||
| if (attrsBlob != null) { | ||
| attrsHolder = SerializationUtil.deserialize(attrsBlob, TreeElement.class); |
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.
Additionally, I think we should have a concrete exception handling strategy for issues here, since deserialization exceptions are probably a very unexpected outcome.
It might be worth doing something like retrieving the byte[] here, and letting the TreeElement get deserialized at a later point (like in get() here: https://github.com/dimagi/commcare-core/pull/842/files#diff-de4be0557361343fe019d6c9b25d8598R38) when we are actively doing reads/deserializations from storage more broadly?
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.
Additionally, I think we should have a concrete exception handling strategy for issues here, since deserialization exceptions are probably a very unexpected outcome.
Do you mean that we don't want the app to crash on such deserialization exceptions and instead show some sort of error message to the user ?
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.
Mostly I mean that having the app crash here in a deserialization exception would be extremely confusing because it would be a symptom of an event that's out of the user's control and would be handled in a very strange part of the lifecycle.
Generally speaking I think it's very, very dangerous for "Utility" classes like this which are static and effectively stateless to throw errors that aren't strongly meaningful at the time. To the programmer, this method looks like it's just receiving a db hook and a string and doing some lookups. The caller wouldn't be expecting to need to be ready to handle mismatched serialized internal models based on the signature and expectations.
That would be their expectation later, however, when they are actually managing the resulting lookup table, so pushing the deserialization code there might be cleaner.
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.
@ctsims Thanks. I get your point now. Though I am struggling to find a better place for the deserialization to go since it requires access to the Prototype factory and hence needs to be in the commcare-android. The get function you linked above is part of commcare-core. The only other place I can forsee is 1 level up i.e. getIndexedFixtureIdentifier but it again has the same semantics issue that doesn't convey to the caller to handle deserialization.
Alternatively, we can decide to not catch DeserializationException in SerializationUtil.deserialize which would add a throws DeserializationException into function signature and hence will be much more evident to a caller function.
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 see what you are saying.
I can't think of a great workaround for now, and it is true that if we broke the TreeElement serialization, we'd need to be fixing the records from scratch anyway.
Maybe the big point of confusion here is just that it doesn't feel right for the attribute holder to be in this record to begin with. Can we make a second version of this method that doesn't pull the attrsHolder so that if we needed to just get the base and child paths, that there's a path for that? Would be good for this version to also throw a typed error specific to this problem so the end user (and us) can see very deliberately that it's an issue with the stored format for retrieving this.
I'm thinking about what pieces we'll need to have in place in a circumstance where we need to migrate fixtures due to a TreeElement serialization format change, and right now this method would just be a blocker.
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.
That makes a lot of sense though just to clarify are you suggesting that we create an unused function/ code path right now because we might need it in future ?
|
@damagatchi retest this please |
3 similar comments
|
@damagatchi retest this please |
|
@damagatchi retest this please |
|
@damagatchi retest this please |
|
@shubham1g5 I think we are both aligned on potential ways forward here, and sorry for all of the back and forth. i'm fine with whatever approach you want to take based on our conversations |
|
@damagatchi retest this please |
1 similar comment
|
@damagatchi retest this please |
|
@ctsims This is ready to get reviewed again. Can you take another look. |
| } | ||
|
|
||
| @Override | ||
| protected AbstractTreeElement setupFixtureData(ExternalDataInstance instance) { |
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.
@shubham1g5 We should make sure that we've also implemented anything we need to implement here for Formplayer.
This may require, for example, require us to bump the version DB (which requires us to clear out Incomplete Forms).
Unrelated to this PR structure, but useful for us to know whether we need to update the Formplayer DB Version # with the next commcare-core pull in that library before merging this one (let me know if this comment doesn't make sense).
ctsims
left a comment
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.
Hey, Shubham,
This looks great. Two small changes specifically in the Lazy Deserialization method, and one higher level question: Have we piloted to make sure FormPlayer works, and whether we need to apply a Version bump before it does (IE: It works out of the box, but if someone has already restore/loaded an indexed fixture, does it work to deserialize that first sandbox)
| return getDeserializedAttributes().getAttributeValue(namespace, name); | ||
| } | ||
|
|
||
| private TreeElement getDeserializedAttributes() { |
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 method needs to be synchronized in the same way as this one:
https://github.com/dimagi/commcare-core/blob/master/src/main/java/org/commcare/cases/instance/StorageInstanceTreeElement.java#L103
to ensure that access to the attributes class is properly managed between threads.
We may want to consider a similar approach to that class where we have one "lazy load method" (there it's called loadElements()) that's called upfront before any methods, rather than specifically presuming that the lazy load is around the attributes.
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.
Made the method synchronized here though I am not sure of any particular benefits of doing deserialization ahead of time, specially since it requires us to be mindful of not accessing the attributes before we call the load on them. For ex. even though loadElements() is designed to be called once at the start we still end up calling it at couple other places.
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.
Hi Shubham,
I think the lazy loading independent of attributes is just a stylistic thing, so fine for it to not be included.
-Clayton
|
|
||
| private TreeElement getDeserializedAttributes() { | ||
| if (attributes == null) { | ||
| attributes = SerializationUtil.deserialize(attrHolder, TreeElement.class); |
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 think we may want to wrap serialization errors here, and specifically rethrow the error (still as a runtimeexception) with a message that says something like "Fixture Root Element Wrapper deserialization failed:" along with the real message, just so when this is seen and reported, we know exactly what is at error.
|
@ctsims I have not checked it on Formplayer yet though assume it will require some changes.
|
On the #2 point there - We don't need to migrate formplayer's db. I am fine continuing to kill the UserDB entirely by updating the version, but I don't think we should know when we are making changes that result in commcare-core being unpullable in FormPlayer in case we needed to manage an urgent issue. |
|
@ctsims Nice points.
|
|
@ctsims bump to look at last set of changes here. |
|
good from my side! |
AndroidIndexedFixtureInstanceTreeElementto support attributes lookup for root attibutes.cross-request: dimagi/commcare-core#842