Parse-SDK-iOS-OSX icon indicating copy to clipboard operation
Parse-SDK-iOS-OSX copied to clipboard

Pinning PFObject with pointer corrupts local datastore

Open mtsanford opened this issue 8 years ago • 26 comments

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 avatar Nov 10 '15 17:11 mtsanford

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. "

mtsanford avatar Nov 10 '15 19:11 mtsanford

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.

richardjrossiii avatar Nov 10 '15 20:11 richardjrossiii

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

mtsanford avatar Nov 10 '15 22:11 mtsanford

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

henrikperrochon avatar Nov 24 '15 12:11 henrikperrochon

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.

ghost avatar Dec 01 '15 17:12 ghost

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!

maricabertarini avatar Dec 07 '15 23:12 maricabertarini

Same issue here.

gloos avatar Dec 10 '15 17:12 gloos

same issue here, really need a solution for that

ghost avatar Jan 31 '16 11:01 ghost

Any update on this issue?

swapsjadhav avatar Feb 18 '16 08:02 swapsjadhav

+1

CiraciNicolo avatar Apr 24 '16 19:04 CiraciNicolo

+1

ranhsd avatar May 10 '16 03:05 ranhsd

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?

edson-gaspar avatar May 10 '16 20:05 edson-gaspar

Can you at least give us some info?

CiraciNicolo avatar May 21 '16 15:05 CiraciNicolo

+1

joshgare avatar May 26 '16 12:05 joshgare

This is killing me

zwergius avatar Jun 01 '16 19:06 zwergius

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.

ghost avatar Jun 01 '16 20:06 ghost

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.

zwergius avatar Jun 07 '16 09:06 zwergius

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.

rob5408 avatar Jul 21 '16 05:07 rob5408

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."

ferrinho avatar Jul 26 '17 10:07 ferrinho

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

wimbledon avatar Jul 26 '17 18:07 wimbledon

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. :)

ferrinho avatar Jul 26 '17 18:07 ferrinho

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

TomWFox avatar Mar 28 '19 16:03 TomWFox

Anyone still dealing with this?

noobs2ninjas avatar Mar 10 '20 16:03 noobs2ninjas

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

tutorbear avatar Mar 11 '20 00:03 tutorbear

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.

bayareahank avatar May 06 '20 06:05 bayareahank

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

loloapodo avatar Aug 19 '20 07:08 loloapodo