realm / realm-swift

Realm is a mobile database: a replacement for Core Data & SQLite
https://realm.io
Apache License 2.0
16.3k stars 2.14k forks source link

Instability with multiple read / writes to Realm #2589

Closed amayne closed 9 years ago

amayne commented 9 years ago

I recently switched over from SQLite to using Realm - and I'm really enjoying the speed improvements, great work! I have found some instability while testing. I am asynchronously writing & updating to one Realm database in a DISPATCH_QUEUE_SERIAL from multiple threads. When writing in the background I get a Realm reference by:

func getRealm() throws -> Realm {
        let realm = try Realm()
        return realm
    }

I found occasionally that the current realm was already in a write transaction, so I wrote a check:

func write(realm: Realm, query: (()->Void)) throws {
        if realm.inWriteTransaction {
            query()
        } else {
            realm.beginWrite()
            query()
            try realm.commitWrite()
        }
    }

I seem to get a bunch of errors when reading & writing as Realm cannot allocate memory: Error Domain=io.realm Code=1 "mmap() failed: Cannot allocate memory" UserInfo={NSLocalizedDescription=mmap() failed: Cannot allocate memory, Error Code=1}

I also occasionally get EXEC_BAD_ACCESS when trying to open another Realm, in this code block (group_shared.hpp):

inline SharedGroup::SharedGroup(Replication& repl, DurabilityLevel durability,
                                const char* encryption_key):
    m_group(Group::shared_tag())
{
    open(repl, durability, encryption_key); // Throws

    upgrade_file_format(); // Throws
}

What am I doing wrong here? I really love the speed I am getting from Realm but the crashes are becoming problematic. Can I not do multiple reads and writes on the database? Should I have multiple Realm databases when doing a large number of reads + writes?

Thanks for your help!

jpsim commented 9 years ago

Hi @amayne, it looks like the device on which you're running Realm in this case is unable to mmap the data Realm needs to perform operations on multiple threads. This can happen when a device is space-constrained, or when Realm files become large enough.

We explain a bit in our FAQ how Realm files can become larger than they should and how to mitigate that (link).

We've also discussed this in some past GitHub issues (#620, #1096, #1159).

The solution in this case is for the Realm initializer to report mmap failures in a recoverable way (#2269), and for different threads to share the same underlying region if it's already mmapped (realm/realm-core#838 and realm/realm-core#876).

Until we have those longer-term solutions, your best bet is to keep Realm files as small as possible (e.g. via compacting) and to run on devices that aren't space-constrained. We understand these are difficult constraints, which is why we're hard at work on the longer term solutions mentioned above.

I believe this issue to be sufficiently tracked elsewhere in its underlying components to close this one as a duplicate.

If you have any questions or comments about this, we'll address them on this thread or wherever else you feel is appropriate.

amayne commented 9 years ago

Thank you @jpsim ! I managed to significantly reduce the size of the Realm by using the file system was storage (I was storing large nsdata in my realm). I am still seeing the errors, but only very occasionally. I will now work towards having this split across multiple realm files and hope that solves all my problems