Skip to content
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

The creation of a Realm instance consistently fails. As a result, the only workaround is to delete the existing data and initialize an empty Realm instance each time. #3674

Open
yashaswinidc opened this issue Sep 17, 2024 · 3 comments

Comments

@yashaswinidc
Copy link

What happened?

When attempting to create a Realm instance, the process fails repeatedly. This results in an inability to use the Realm database as intended. The only solution has been to wipe the existing data and create a new, empty Realm instance, which is not ideal and indicates an underlying issue with the instance creation process.

Repro steps

Steps to Reproduce:
Attempt to create a Realm instance using the provided RealmConfiguration.
Observe the failure in instance creation.

Note: This was working in Xamarin. Now I am getting issue in MAUI

Expected Behavior: The Realm instance should be created successfully without requiring data deletion or reinitialization.

Actual Behavior: Instance creation fails consistently, necessitating a manual deletion of data and the creation of an empty Realm instance.

Version

8.0

What Atlas Services are you using?

Local Database only

What type of application is this?

Other

Client OS and version

12.2.0

Code snippets

using System.Reactive.Linq;
using Realms;
using Realms.Exceptions;

namespace Core.Storage
{
public delegate T Transaction(Realm realm);

public delegate IQueryable<T> Query<T>(IQueryable<T> query);

public abstract class RealmStorage : IStorage
{
    protected Realm Realm => GetRealmInstance();

    protected abstract RealmConfiguration RealmConfiguration { get; }

    private Realm GetRealmInstance()
    {
        const int maxRetries = 3;
        int retryCount = 0;

        while (retryCount < maxRetries)
        {
            try
            {
                var realmInstance = Realm.GetInstance(RealmConfiguration);
                return realmInstance;
            }
            catch (RealmInvalidDatabaseException ex)
            {
                Console.WriteLine($"Realm invalid database error: {ex.Message}");

                // Delete the corrupted Realm file
                string realmPath = RealmConfiguration.DatabasePath;
                if (File.Exists(realmPath))
                {
                    File.Delete(realmPath);
                    Console.WriteLine("Deleted corrupted Realm file.");
                }

                // Try to recreate the Realm instance
                try
                {
                    var realmInstance = Realm.GetInstance(RealmConfiguration);
                    Console.WriteLine("Successfully recreated Realm instance.");
                    return realmInstance;
                }
                catch (Exception recreateEx)
                {
                    Console.WriteLine($"Failed to recreate Realm instance: {recreateEx.Message}");
                    throw new Exception("Failed to recreate the Realm instance after deleting the corrupted file.", recreateEx);
                }
            }
            catch (RealmFileAccessErrorException ex)
            {
                Console.WriteLine($"Realm file access error: {ex.Message}");
                throw new Exception("Failed to access the Realm file. Ensure the file exists and the application has the necessary permissions.", ex);
            }
            catch (Exception ex)
            {
                retryCount++;
                if (retryCount < maxRetries)
                {
                    Console.WriteLine($"Retrying... ({retryCount}/{maxRetries})");
                    ResetRealmDatabase();
                    System.Threading.Thread.Sleep(1000);
                }
                else
                {
                    Console.WriteLine($"General exception when getting Realm instance: {ex.Message}");
                    throw new Exception("An unexpected error occurred while getting the Realm instance.", ex);
                }
            }
        }

        // This line will be reached only if all retries failed
        throw new Exception("An unexpected error occurred while getting the Realm instance after all retry attempts.");
    }

    private void ResetRealmDatabase()
    {
        try
        {
            // Delete the corrupted Realm file
            string realmPath = RealmConfiguration.DatabasePath;
            if (File.Exists(realmPath))
            {
                File.Delete(realmPath);
                Console.WriteLine("Deleted corrupted Realm file.");
            }

            // Recreate Realm instance
            var realmInstance = Realm.GetInstance(RealmConfiguration);
            Console.WriteLine("Successfully recreated Realm instance.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to reset Realm database: {ex.Message}");
            throw new Exception("Failed to recreate Realm after deleting the corrupted file.", ex);
        }
    }

    public IObservable<IList<T>> List<T>() where T : RealmObject
    {
        return Observable.Create<IList<T>>(emitter =>
        {
            try
            {
                var entities = Realm.All<T>()
                                    .ToList()
                                    .Select(e => e.Copy())
                                    .ToList();

                emitter.OnNext(entities);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error listing entities: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }

    public IObservable<T> Find<T>(string id) where T : RealmObject
    {
        return Observable.Create<T>(emitter =>
        {
            try
            {
                var entity = Realm.Find<T>(id);
                emitter.OnNext(entity?.Copy());
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error finding entity by string ID: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }

    public IObservable<T> Find<T>(long id) where T : RealmObject
    {
        return Observable.Create<T>(emitter =>
        {
            try
            {
                var entity = Realm.Find<T>(id);
                emitter.OnNext(entity?.Copy());
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error finding entity by long ID: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }

    public IObservable<int> Delete<T>(long id) where T : RealmObject
    {
        return Observable.Create<int>(emitter =>
        {
            try
            {
                var realm = Realm;
                var entity = realm.Find<T>(id);

                if (entity != null)
                {
                    realm.Write(() =>
                    {
                        realm.Remove(entity);
                    });
                }

                emitter.OnNext(entity == null ? 0 : 1);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error deleting entity: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }

    public IObservable<T> InsertOrReplace<T>(T entity) where T : RealmObject
    {
        return ExecuteInTransaction(realm =>
        {
            try
            {
                return realm.Add(entity.Copy(), true).Copy();
            }
            catch (RealmException ex)
            {
                Console.WriteLine($"Realm exception during insert or replace: {ex.Message}");
                throw;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"General exception during insert or replace: {ex.Message}\n{ex.StackTrace}");
                throw;
            }
        });
    }

    public IObservable<IList<T>> InsertOrReplace<T>(IList<T> entities) where T : RealmObject
    {
        return ExecuteInTransaction(realm =>
        {
            try
            {
                var result = new List<T>(entities.Count);
                foreach (var entity in entities)
                {
                    result.Add(realm.Add(entity, true).Copy());
                }
                return result;
            }
            catch (RealmException ex)
            {
                Console.WriteLine($"Realm exception during bulk insert or replace: {ex.Message}");
                throw;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"General exception during bulk insert or replace: {ex.Message}\n{ex.StackTrace}");
                throw;
            }
        });
    }

    public IObservable<int> DeleteAll<T>() where T : RealmObject
    {
        return ExecuteInTransaction(realm =>
        {
            try
            {
                var query = realm.All<T>();
                int count = query.Count();
                realm.RemoveRange(query);
                return count;
            }
            catch (RealmException ex)
            {
                Console.WriteLine($"Realm exception during delete all: {ex.Message}");
                throw;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"General exception during delete all: {ex.Message}\n{ex.StackTrace}");
                throw;
            }
        });
    }

    public IObservable<IList<T>> Select<T>(Query<T> query) where T : RealmObject
    {
        return Observable.Create<IList<T>>(emitter =>
        {
            try
            {
                var queryable = Realm.All<T>();
                var result = query.Invoke(queryable)
                                  .ToList()
                                  .Select(e => e.Copy())
                                  .ToList();

                emitter.OnNext(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error selecting entities: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }

    public IObservable<int> Delete<T>(Query<T> criteria) where T : RealmObject
    {
        return ExecuteInTransaction(realm =>
        {
            try
            {
                var query = criteria.Invoke(realm.All<T>());
                int count = query.Count();
                realm.RemoveRange(query);
                return count;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error deleting entities by criteria: {ex.Message}");
                throw;
            }
        });
    }

    public IObservable<T> ExecuteInTransaction<T>(Transaction<T> trx)
    {
        return Observable.Create<T>(emitter =>
        {
            try
            {
                var result = default(T);

                var realm = Realm;
                realm.Write(() =>
                {
                    result = trx.Invoke(realm);
                });

                emitter.OnNext(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error executing transaction: {ex.Message}");
                emitter.OnError(ex);
            }
            emitter.OnCompleted();
            return () => { };
        });
    }
}

}

Stacktrace of the exception/crash you're getting

Message	"An unexpected error occurred while getting the Realm instance."	
StackTrace "at Core.Storage.RealmStorage.GetRealmInstance() in /Users/yashaswinidc/.../Core/Storage/RealmStorage.cs:line 57\n   at Core.Storage.RealmStorage.get_Realm()

Relevant log output

No response

Copy link

sync-by-unito bot commented Sep 17, 2024

➤ PM Bot commented:

Jira ticket: RNET-1176

@nirinchev
Copy link
Member

Can you share the original exception you're getting rather than the one you're throwing yourself?

@yashaswinidc
Copy link
Author

e {System.Exception: An unexpected error occurred while getting the Realm instance. ---> System.AggregateException: One or more errors occurred. (One or more errors occurred. (Exception of type 'Javax.Crypto.AEADBadTagException' was thrown.)) ---> System.Aggreg…}
Data {System.Collections.ListDictionaryInternal}
HResult -2146233088
HelpLink (null)
InnerException Count = 1
Message "An unexpected error occurred while getting the Realm instance."
Source "Core"
StackTrace " at Core.Storage.RealmStorage.GetRealmInstance() in /Users/yashaswinidc/...r/Core/Storage/RealmStorage.cs:line 57\n at Core.Storage.RealmStorage.get_Realm() in /Users/yashaswinidc/.../Core/Sto…"
TargetSite {Realms.Realm GetRealmInstance()}

this is the exception data for android, No message or log is throw'ed from our code. 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants