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

dev.morphia.Datastore Thread Safety #3035

Open
MKaramavrov opened this issue May 14, 2024 Discussed in #2802 · 5 comments
Open

dev.morphia.Datastore Thread Safety #3035

MKaramavrov opened this issue May 14, 2024 Discussed in #2802 · 5 comments

Comments

@MKaramavrov
Copy link

Discussed in #2802

Originally posted by AmitKuGarg December 18, 2023
Describe the bug
When dev.morphia.Datastore shared across thread, I get Two entities have been mapped using the same discriminator value.

To Reproduce
Steps to reproduce the behavior:

  1. Create a sample collection and create the datastore.
    Datastore datastore = Morphia.createDatastore(mongo, dbName);
    datastore.ensureIndexes();
    if(this.packages != null){
    for (String packageString : packages) {
    datastore.getMapper().map(packageString);
    }
    }

  2. Create a runnable class and pass the data store and id parameter. In run method load the data from the collection using id and datastore.
    class Task implements Runnable {
    private String id;
    private Datastore mongoDatastore;

    Task(String id, Datastore mongoDatastore) {
    this.id = id;
    this.mongoDatastore = mongoDatastore;
    }

    @OverRide
    public void run() {

     Sample result = mongoDatastore.find(Sample.class).filter(Filters.eq("_id", id)).first();        
     if(result == null){
         System.out.println("Result is null");
     }else {
         System.out.println(result.toString());
     }
    

    }
    }

  3. Write main method, create ExecutorService and try to load different documents.
    ExecutorService executor = Executors.newFixedThreadPool(10);
    executor.execute(new Task("ABC12345", mongoDatastore));
    executor.execute(new Task("ABC123456", mongoDatastore));

I get Two entities have been mapped using the same discriminator value.

Try two scenario

  1. When ids are valid id from collection
  2. Try some invalid ids where collection return null.
@MKaramavrov
Copy link
Author

In our project, we faced the same issue with lazy mapping of the entities during runtime. Version, which we currently use is 2.4.11.

@evanchooly
Copy link
Member

I'm hesitant to do too much thread-safety work here as this is a very common method to call. A better fix, on your end, is to not rely on lazy mapping (especially as that is going away) and explicitly map your classes/packages up front. This should eliminate your issues. Please try pre-mapping and see if your issue goes away. If it doesn't, we can talk about this PR.

@MKaramavrov
Copy link
Author

That was already a discussion here: #2802
Would be nice to have a fix at least for 2.4.x version, because we've just migrated from version 1.6.x to 2.4.11 and we are currently trying to preregister every entity on startup, but there is conceptual issue, because morphia does not enforce preregistration and during code change someone can miss some entity which will lead to hard to catch and reproduce issue.

@MKaramavrov
Copy link
Author

@evanchooly Could we please consider fixing the issue at least for 2.4.x versions?
Not sure that we will have too much thread safety, as we are checking for presence of existing model before making it synchronized:

if (existing != null) {
            return existing;
        }

@aksdb
Copy link

aksdb commented Nov 29, 2024

We also run into this issue during our migration from 1.6 to 2.4.

We also pre-register our entities during startup, but it looks like getEntityModel on a "root"-entity doesn't cause the embedded entities to be registered, which then still happens on the first save() call which then can lead to concurrency issues.

Mapping all entities upfront wouldn't really work either, since each datasource has its own mapper with Morphia 2.4. If we map all entities on all datasources, that seems quite inefficient (especially since most entities wouldn't be used on all datasources).

I don't quite understand why no read/write mutex is used for this, if this is so critical.

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

3 participants