Skip to content

Pinning PFObject with pointer corrupts local datastore #535

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

Open
mtsanford opened this issue Nov 10, 2015 · 26 comments
Open

Pinning PFObject with pointer corrupts local datastore #535

mtsanford opened this issue Nov 10, 2015 · 26 comments

Comments

@mtsanford
Copy link

Tested on version 1.9.1. If an object C1 pointing to P1 is pinned (and not saved), then an object C2 pointing to P2 is pinned, P1 is corrupted in the datastore. This seems to be the minimum condition to reproduce:

func letsCorruptTheDatastore(sender: AnyObject) {

        // create a post with a comment and pin it
        let post1 = PFObject(className:"Post")
        post1["text"] = "I am post #1"
        let comment1 = PFObject(className:"Comment")
        comment1["post"] = post1

        comment1.pinInBackground().continueWithSuccessBlock {
            (task: BFTask!) -> AnyObject! in

            // Make another post with comment and pin it
            let post2 = PFObject(className:"Post")
            post2["text"] = "I am post #2"
            let comment2 = PFObject(className:"Comment")
            comment2["post"] = post2
            return comment2.pinInBackground()
        }.continueWithSuccessBlock {
            (task: BFTask!) -> AnyObject! in

            // Now try to query local Post objects
            let query = PFQuery(className:"Post")
            query.fromLocalDatastore()
            return query.findObjectsInBackground()
        }.continueWithBlock {
            (task: BFTask!) -> AnyObject! in
            if (task.error != nil) { print(task.error) }
            else if (task.result != nil) { print(task.result) }
            return nil 
        } 
    }

The query fails with this error:

Error Domain=Parse Code=120 "Attempted to fetch and object offline which was never saved to the offline cache" UserInfo={error=Attempted to fetch and object offline which was never saved to the offline cache, code=120, NSLocalizedDescription=Attempted to fetch and object offline which was never saved to the offline cache}

Looking at the sqlite database, it is apparent that the data has been corrupted (nulled out), which results in queries on the corrupted data always failing.

sqlite> 
sqlite> select * from ParseObjects where className = "Post";
41067A2D-5BE8-4BD8-8902-C453E790C69B|Post||{"className":"Post","__complete":true,"__operations":[{"__updatedAt":{"iso":"2015-11-10T16:58:07.687Z","__type":"Date"},"__uuid":"FD2A80A9-7E9F-469E-95DC-2DF4A0014361","text":"I am post #2"}],"isDeletingEventually":0}|0
616B0182-1A5B-4F44-BE05-204A80AAE557|Post|||0
sqlite> select * from ParseObjects where className = "Comment";
B847E0D4-725A-464D-AEA9-51D4CADCD66A|Comment||{"className":"Comment","__complete":true,"__operations":[{"__updatedAt":{"iso":"2015-11-10T16:58:07.691Z","__type":"Date"},"post":{"uuid":"616B0182-1A5B-4F44-BE05-204A80AAE557","__type":"OfflineObject"},"__uuid":"546E9AEF-63B7-460A-A130-BD547D11DB45"}],"isDeletingEventually":0}|0
AB5FAF2A-C698-4A4F-8011-1FC3602247D3|Comment||{"className":"Comment","__complete":true,"__operations":[{"__updatedAt":{"iso":"2015-11-10T16:58:07.688Z","__type":"Date"},"post":{"uuid":"41067A2D-5BE8-4BD8-8902-C453E790C69B","__type":"OfflineObject"},"__uuid":"D58AAEEE-093F-4C71-B002-F6F10B3E05D5"}],"isDeletingEventually":0}|0
sqlite> 
@mtsanford
Copy link
Author

digging a little deeper, it appears that first pin is not even done correctly, and that the bug is in pinning objects with pointers. After just saving a single Comment pointing to a Post, the sqlite database contains this data:

BD07816F-F2AA-4DC1-9807-BC191FCE58C8|_Pin||{"className":"_Pin","__complete":true,"__operations":[{"_objects":[{"uuid":"88B8BFB7-E56A-49E4-81FD-FC836897AE77","__type":"OfflineObject"}],"__uuid":"19FFB7FD-534F-4BFB-B6C8-EF17B16919C5","_name":"_currentUser","__updatedAt":{"iso":"2015-11-10T19:42:41.601Z","__type":"Date"}}],"isDeletingEventually":0}|0
88B8BFB7-E56A-49E4-81FD-FC836897AE77|_User||{"className":"_User","__complete":true,"__operations":[{"__uuid":"7A490326-1421-40B6-B867-EB13C346DA13","__updatedAt":{"iso":"2015-11-10T19:42:41.594Z","__type":"Date"}}],"isDeletingEventually":0}|0
7A2C3F1F-9DB7-4566-AFE1-0C26D02ABC1F|_Pin||{"className":"_Pin","__complete":true,"__operations":[{"_objects":[{"uuid":"8F91E10D-80CD-43DE-86E7-EFCB8BC81F88","__type":"OfflineObject"}],"__uuid":"24E5AEE3-1417-4BDE-A129-59907AA22574","_name":"_default","__updatedAt":{"iso":"2015-11-10T19:43:21.446Z","__type":"Date"}}],"isDeletingEventually":0}|0
9DD18DC7-D153-469A-8636-3DF1B5CA9B02|Post||{"className":"Post","__complete":true,"__operations":[{"__updatedAt":{"iso":"2015-11-10T19:43:21.443Z","__type":"Date"},"__uuid":"4242605C-52D6-4709-B02C-C42423C3B5E7","text":"I am another post"}],"isDeletingEventually":0}|0
8F91E10D-80CD-43DE-86E7-EFCB8BC81F88|Comment||{"className":"Comment","__complete":true,"__operations":[{"__updatedAt":{"iso":"2015-11-10T19:43:21.443Z","__type":"Date"},"post":{"uuid":"9DD18DC7-D153-469A-8636-3DF1B5CA9B02","__type":"OfflineObject"},"__uuid":"FC33D3E3-B185-45D3-B17C-EE26971B62E4"}],"isDeletingEventually":0}|0
sqlite> 

The second pin (7A2C3F1F...) appears to include the Comment (8F91E10D...) in it's list of objects, but not the Post it points to (9DD18DC7...). Although maybe I'm not fulling understanding how pinning is implemented.

In the documentation it states: "Pinning a PFObject is recursive, just like saving, so any objects that are pointed to by the one you are pinning will also be pinned. "

@richardjrossiii
Copy link
Contributor

This seems related to #239, though I don't have the slightest clue what could be causing this.

LocalDataStore is a very complex beast. and it's very possible there exists a pointer encoding bug there. I'll look into it.

And - thank you for the super clear repro case, it makes investigating this super easy.

@mtsanford
Copy link
Author

OK, thanks. It looks like explicitly pinning referenced objects is a good workaround for now.

@henrikperrochon
Copy link

Hi,
I've faced the same issue. I've used another workaround which is pinning with specific name.
Have a nice day!

@ghost
Copy link

ghost commented Dec 1, 2015

I have this problem too and I am already pinning with specific names. My object contains pointers that have pointers to other objects. When I initially pin them, they save correctly. But if I pin another object of the same type, they are all removed, and querying the local datastore returns nothing.

@maricabertarini
Copy link

Hi,
any news? I am experiencing the same on Android. I pin in bg an object that contains an array of pointers. Then, when I query for this kind of objects and I use include to retrieve pointers, I get error with code 120 and message Message: This object is not available in the offline cache.
Thanks for your help!

@gloos
Copy link

gloos commented Dec 10, 2015

Same issue here.

@ghost
Copy link

ghost commented Jan 31, 2016

same issue here, really need a solution for that

@swapsjadhav
Copy link

Any update on this issue?

@CiraciNicolo
Copy link

+1

1 similar comment
@ranhsd
Copy link

ranhsd commented May 10, 2016

+1

@edson-gaspar
Copy link

I'm sad with Parse local store. I need to finish an App ASAP and its very danger to persist my objects to sync later. Now I'm trying to implement my offline storage with IBM Cloudant or RealmSwift constructing a bridge on models to sync with Parse when data is committed. Please, could someone have another idea or its a good start?

@CiraciNicolo
Copy link

Can you at least give us some info?

@joshgare
Copy link

+1

@zwergius
Copy link

zwergius commented Jun 1, 2016

This is killing me

@ghost
Copy link

ghost commented Jun 1, 2016

I rember what fixed this for me! The problem was that I was pinning an object where some of the data hadn't been fetched. That resulted in a completely null object. So try fetching every referenced object first, and fetch the object itself, and then pin. Print out the data first to check its all there. If any object or pointed object doesn't contain data, the pin will result in a null ref.

@zwergius
Copy link

zwergius commented Jun 7, 2016

Thanks for the suggestion, in the end it was me doing it wrong - I was including some objects in a query and not pinning all of them.

@rob5408
Copy link

rob5408 commented Jul 21, 2016

This fixed it for me, which is maddening as the documentations says...

Pinning a PFObject is recursive, just like saving, so any objects that are pointed to by the one you are pinning will also be pinned.

https://www.parse.com/docs/ios/guide#local-datastore-pinning

Is a Pointer not considered "pointed to"? Strangely pinning an object with a property that is an Array of Pointers seems to be working fine.

I guess I should check the documentation for the OSS codebase as well.

@ferrinho
Copy link

ferrinho commented Jul 26, 2017

any news on this? I'm getting the same error... I have includeKeys on both server and offline queries. The local queries work fine on the beginning, but then when I pin or unpin some objects "withName", and redo local query, I get this error. "This object is not available in the offline cache."

@wimbledon
Copy link

Same issue here. It's a terrible experience when user's data is gone.

@ferrinho
Copy link

I've put some more work into this... I'm not sure if I found a replicable pattern, but it seems like every time I pin objects back to the database, local queries work again... in my specific case, this happens:

  1. Server Query and pin all with name. Now local queries are working.
  2. unpin and deleteEventually (corrupts database and I can no longer do local queries). Note that local queries without "includeKey" still work fine.
  • Sometimes, when pinning a object, it all get's working again, but I can't yet trust this behavior.
    My workaround, for now, is when I receive the referenced error, I query the server, then redo local query and it works again. Since it seems to only happen when unpinning objects, if user move around the app and not remove data, it will work local and no server queries. At least I get some speed when changing screens and loading data.

Well, I'm still waiting for a solution. :)

@TomWFox
Copy link
Contributor

TomWFox commented Mar 28, 2019

@ferrinho @wimbledon @rob5408 @Zwerge Are any of you still experiencing this issue?

@noobs2ninjas
Copy link
Member

Anyone still dealing with this?

@tutorbear
Copy link

tutorbear commented Mar 11, 2020

Me , Horrible freaking experience , This object is not available in the offline cache is my error.
Only thing that solved it for me was using specific pin names for every object.
And one important thing to note, at first i was pinning using the objectId of the objects but later saw unpinning dosent work. I came to find that using objectId any string that long renders the pin label invalid thus unpin dosent work. So i suggest to keep pin labels as small as possible and to avoid pointers as much as possible

@bayareahank
Copy link

bayareahank commented May 6, 2020

I am having similar issues with pin to local store.

In one case, I read records (with pointers) from DB, and then put them into a local set. When two distinct records bear the same logical (in business) IDs, they would count equal in the data set, and one would be discarded. This discard would ruin the local store, and subsequent query would report error saying "not available in offline cache". I removed this duplicate record (in business, not data sense), then local query starts working. This shouldn't be this fragile.

Another case I am debugging is pinned data (with pointers, if that matters) missing from data store, even do query immediately after pin. This doesn't always happen, but sure frustrating when it does. BTW, I am using parse-ios-sdk 1.17.3.

It looks I need to find a replacement for local storage, to not lose customer data. Any suggestion would be appreciated.

@loloapodo
Copy link

Had the same issue. Before get any field from the pointer call:
myparseobject.fetchFromLocalDatastore();

I pinned before do that. Not know directly with network.
Remeber before do pin to include the pointer name in the query

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

No branches or pull requests