Skip to content

SDK locking #646

Open
Open
@natario1

Description

@natario1

I had some time to investigate an issue that looks serious.
I think the SDK hangs with a deadlock somewhere when doing too many operations concurrently, where too many depends on the device but is a pretty low number (even down to 3).

Working case

The concurrent policy is managed by bolts in this class. You can see that CORE_POOL_SIZE is the number of processors + 1.

When you schedule too much operation and exceed the pool size, tasks are scheduled. You can see this in action calling this function:

private Task<Void> tryHangingWithBolts() {
    List<Task<Void>> tasks = new ArrayList<>();
    for (int i = 0; i < 50; i++) {
        final int num = i;
        tasks.add(Task.callInBackground(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Log.e("Bolts", "About to start task "+num);
                Task.delay(3000).waitForCompletion();
                Log.e("Bolts", "Finished task "+num);
                return null;
            }
        }));
    }
    return Task.whenAll(tasks);
}

This starts 50 operations concurrently. Each operation will just wait for 3 seconds. This works. It’s also nice to look at the logs because you get to see how the bolts executor works.

About to start task 1
About to start task 0
About to start task 4
About to start task 3
About to start task 6
About to start task 5
About to start task 2
Finished task 1
Finished task 4
Finished task 3
About to start task 8
About to start task 7
About to start task 9
Finished task 0
About to start task 10 ... and so on

My device has 6 processors, so the core pool size is 7. I can see in logs that the first 7 tasks are started, then there’s a delay because the pool is full, then some tasks end and new tasks are added and executed. With a reasonable delay, all 50 tasks are executed.

Hanging case

If you replace my fake tasks with parse tasks, the SDK hangs completely and indefinitely after the pool is full. For example, here I get 10 objects through query, and then call fetch() on each of these at the same time.

private Task<Void> tryHangingWithParse() {
    // get objects from query first
    ParseQuery<ParseObject> query = new ParseQuery<>("Tag");
    query.setLimit(10);
    return query.findInBackground().onSuccessTask(new Continuation<List<ParseObject>, Task<Void>>() {
        @Override
        public Task<Void> then(Task<List<ParseObject>> task) throws Exception {
            // We have objects. Fetch them concurrently.
            List<ParseObject> objectsToFetch = task.getResult();
            List<Task<Void>> tasks = new ArrayList<>();
            int count = 0;
            for (final ParseObject o : objectsToFetch) {
                final int currCount = count;
                tasks.add(Task.callInBackground(new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        Log.e("Parse", "About to fetch object "+currCount);
                        o.fetch();
                        Log.e("Parse", "Fetched object "+currCount);
                        return null;
                    }
                }));
                count++;
            }
            return Task.whenAll(tasks);
        }
    });
}

This is the output though:

About to fetch object 0
About to fetch object 1
About to fetch object 2
About to fetch object 3
About to fetch object 5
About to fetch object 6
About to fetch object 4

Just 7. And nothing more, forever. No objects is fetched, not even those belonging to the first tasks. Other tasks are not scheduled. After this operation, the SDK is locked permanently.

It’s not uncommon to practically end up in this situation. E.g. displaying a list that fetches child objects onBind. And with a low end device / slow connection, this is much more frequent.

Can you reproduce this @rogerhu @Jawnnypoo @hermanliang ? I have no idea what’s happening and why.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions