From 44a10bb0e188517d972c2d9f06b4d00683fedd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 15 Dec 2015 12:55:34 +0100 Subject: [PATCH 1/8] documentatino update --- MorphiumDoku.md | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/MorphiumDoku.md b/MorphiumDoku.md index 72a99bbc1..ac22b949b 100644 --- a/MorphiumDoku.md +++ b/MorphiumDoku.md @@ -3,6 +3,9 @@ Author: Stephan Bösebeck URL: http://sboesebeck.github.io/morphium/ morphium_version: 3.0 mongodb_version: 3.2 +html header: + + ... # Morphium Documentation @@ -82,8 +85,9 @@ As you know the motivation now, these are the changes. Simple example on how to use *Morphium*: -First you need to create Data to be stored in Mongo. This should be some simple class like this one here: +First you need to create data to be stored in Mongo. This should be some simple class like this one here: +``` @Entity public class MyEntity { @Id @@ -93,13 +97,13 @@ First you need to create Data to be stored in Mongo. This should be some simple private long property; //.... getter & setter here } - +``` -This given Entity has a couple of fields which will be stored in Mongo according to their names. Usually the Collection Name is also derived from the ClassName (as most things in *Morphium*, that can be changed). +This given entity has a couple of fields which will be stored in Mongo according to their names. Usually the collection name is also derived from the ClassName (as most things in *Morphium*, that can be changed). -The names are usually translated from camel case (like `aField`) into lowercase with underscores (like `a_field`). This is the default behavior, but can be changed to your needs. +The names are usually translated from camel case (like `aField`) into lowercase with underscores (like `a_field`). This is the default behavior, but can be changed according to your needs. -In Mongo the corresponding object would be stored in a collection named `my_entity` and would look like this: +In mongo the corresponding object would be stored in a collection named `my_entity` and would look like this: { _id: ObjectId("53ce59864882233112aa018df"), @@ -118,7 +122,8 @@ The next example shows how to store and access data from mongo: //connect to a replicaset //if you want to connect to a shared environment, you'd add the addresses of //the mongos-servers here - //you can also specify only one of those nodes, Morphium will figure out the others + //you can also specify only one of those nodes, + //Morphium (or better: mongodb driver) will figure out the others //connect Morphium morphium=new Morphium(cfg); @@ -130,17 +135,17 @@ The next example shows how to store and access data from mongo: morphium.store(ent); //the query object is used to access mongo - Query q=morphium.createQueryFor(MyEntity.class); + Query q=morphium.createQueryFor(MyEntity.class); q=q.f("a_field").eq(123); q=q.f("other").eq("value"); q=q.f("property").lt(123).f("property").gt(100); - List lst=q.asList(); + List lst=q.asList(); //or use iterator for (MyEntity e:q.asIterable(100,2)) { // iterate in windows of 100 objects - // 3 windows lookAhead + // 2 windows lookAhead } @@ -152,17 +157,25 @@ This gives a short glance of how *Morphium* works and how it can be used. But *M There are four major components of *Morphium*: -1. the *Morphium* Instance: This is you main entrypoint for interaction with Mongo. Herer you create Queries and you write data to mongo. All writes will then be forwareded to the configured Writer implementation, all reads are handeled by Query +1. the *Morphium* Instance: This is you main entrypoint for interaction with Mongo. Here you create Queries and you write data to mongo. All writes will then be forwarded to the configured Writer implementation, all reads are handled by the Query-Object 2. Query-Object: you need a query object to do reads from mongo. This is usually created by using `Morphium.createQueryFor(Class cls)`. With a Query, you can easily get data from database or have some things changed (update) and alike. 3. the Cache: For every request that should be sent to mongo, *Morphium* checks first, whether this collection is to be cached and if there is already a result being stored for the corresponding request. -4. The Writers: there are 3 different types of writers in *Morphium*: The Default Writer (`MorphiumWriter`) - writes directly to database, waiting for the response, the BufferedWriter (`BufferedWriter`) - does not write directly. All writes are stored in a Buffer which is then processed as a bulk. The last type of writer ist the asynchronous writer (`AsyncWriter`) which is similar to the buffered one, but starts writing immediately - only asynchronous. *Morphium* decides which writer to use depending on the configuration an the annotations of the given Entities. +4. The Writers: there are 3 different types of writers in *Morphium*: The Default Writer (`MorphiumWriter`) - writes directly to database, waiting for the response, the BufferedWriter (`BufferedWriter`) - does not write directly. All writes are stored in a buffer which is then processed as a bulk. The last type of writer ist the asynchronous writer (`AsyncWriter`) which is similar to the buffered one, but starts writing immediately - only asynchronous. *Morphium* decides which writer to use depending on the configuration an the annotations of the given Entities. But you can _always_ use asynchronous calls just by adding a`AsyncCallback` implementation to your request. Simple rule when using *Morphium*: You want to read -> Use the Query-Object. You want to write: Use the *Morphium* Object. There are some additional features built upon this architecture: * messaging: *Morphium* has a own messaging system. -* cache synchronization: Synchronize caches in a clustered environment. +* cache synchronization: Synchronize caches in a clustered environment. Uses messaging +* custom mappers - you can tell *Morphium* how to map a certain type from and to mongodb. For example there is a "custom" mapper implementation for mapping `BigInteger` instances to mongodb. +* every of those implementations can be changed: it is possible to set the class name for the `BufferedWriter` to a custom built one (in `MorphiumConfig`). Also you could replace the object mapper with your own implementation by implementing the `ObjectMapper` interface and telling morphium which class to use instead. In short, these things can be changed in morphium / morphiumconfig: + * MorphiumCache + * ObjectMapper + * Query + * Field + * QueryFactory + * Driver (> V3.0) * Object Mapping from and to Strings (using the object mapper) ## Configuring *Morphium* From c1629f6946bfbee36bd9389c3c208ad1bb0dd7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 15 Dec 2015 13:04:52 +0100 Subject: [PATCH 2/8] create html documentation from md file --- .gitignore | 1 + create_html_doc.sh | 3 +++ 2 files changed, 4 insertions(+) create mode 100755 create_html_doc.sh diff --git a/.gitignore b/.gitignore index 76d8a838f..3cc2d7685 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ target/ *.iml dist/ *.orig +MorphiumDoku.html diff --git a/create_html_doc.sh b/create_html_doc.sh new file mode 100755 index 000000000..6a506568d --- /dev/null +++ b/create_html_doc.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +multimarkdown -t html MorphiumDoku.md -o MorphiumDoku.html From 75c8ca9e5b498f29783188795b6a6fee7e46c050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 15 Dec 2015 15:02:03 +0100 Subject: [PATCH 3/8] dokumentation updates --- MorphiumDoku.md | 90 ++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/MorphiumDoku.md b/MorphiumDoku.md index ac22b949b..740fd8b18 100644 --- a/MorphiumDoku.md +++ b/MorphiumDoku.md @@ -10,9 +10,11 @@ html header: all(List - public Query eq(Object val); - public Query ne(Object val); - public Query size(int val); - public Query lt(Object val); - public Query lte(Object val); - public Query gt(Object val); - public Query gte(Object val); - public Query exists(); - public Query notExists(); - public Query mod(int base, int val); - public Query matches(Pattern p); - public Query matches(String ptrn); - public Query type(MongoType t); - public Query in(Collection vals); - public Query nin(Collection vals); /** @@ -382,14 +377,12 @@ The `f` method stands for "field" and returns a *Morphium* internal representati * @return the query */ public Query near(double x, double y, double maxDistance); - + /** * search for entries with geo coordinates wihtin the given rectancle - x,y upper left, x2,y2 lower right corner */ public Query box(double x, double y, double x2, double y2); - public Query polygon(double... p); - public Query center(double x, double y, double r); /** @@ -402,19 +395,13 @@ The `f` method stands for "field" and returns a *Morphium* internal representati */ public Query centerSphere(double x, double y, double r); - public Query getQuery(); - public void setQuery(Query q); - public ObjectMapper getMapper(); - public void setMapper(ObjectMapper mapper); - - public String getFieldString(); - + public String getFieldString(); public void setFieldString(String fld); - +``` Query definitions can be in one line, or as above in several lines. Actually the current query object is changed with every call of `f...something` combination. The current object is always returned, for making the code more ledgeable and understandable, you should assign the query as shown above. This makes clear: "The object changed" @@ -424,8 +411,10 @@ As already mentioned, the query by default creates AND-queries. If you need to c `or` takes a list of queries as argument, so a query might be built this way: -`Query q=morphium.createQueryFor(MyEntity.class); - q=q.or(q.q().f("counter").le(10),q.q().f("name").eq("Morphium"));` +``` + Query q=morphium.createQueryFor(MyEntity.class); + q=q.or(q.q().f("counter").le(10),q.q().f("name").eq("Morphium")); +``` This would create an OR-Query asking for all "MyEntities", that have a counter less than or equal to 10 OR whose name is "Morphium". You can add as much or-queries as you like. OR-Queries can actually be combined with and queries as well: @@ -435,6 +424,14 @@ This would create an OR-Query asking for all "MyEntities", that have a counter l In that case, the query would be something like: counter is greater than 2 AND (counter is less then or equal to 10 OR name is "Morphium") +Combining and and or-queries is also possible, although the syntax would look a bit unfamiliar: + +``` + Query q=morphium.createQueryFor(MyEntity.class); +q=q.f("counter").lt(100).or(q.q().f("counter").mod(3,0),q.q().f("value").ne("v"); +``` +This would create a query returning all entries that do have a `counter` of less than 100 AND where the modulo to base 3 of the value `counter` equals 0, and the value of the field `value` equals "v". + Quite complex, eh? Well, there is more to it... it is possible, to create a query using a "where"-String... there you can add `JavaScript` code for your query. This code will be executed at the mongodb node, executing your query: @@ -442,11 +439,11 @@ Well, there is more to it... it is possible, to create a query using a "where"-S `Query q=morphium.createQueryFor(MyEntity.class); q=q.where("this.counter > 10");` -Attention: you can javascript code in that where clause, but you cannot access the `db` object there. This was changed when switching to Mongodb 2.6 with V8 Javascript engine +**Attention**: you can javascript code in that where clause, but you cannot access the `db` object there. This was changed when switching to Mongodb 2.6 with V8 Javascript engine ## Declarative Caching -Using the `@Cache` annotation, you can define cache settings on a per type (= class) basis. This is done totally in background, handeled by *Morphium* 100% transparently. You just add the annotation to your entities and you're good to go. See [Cache] and [Cache Synchronization] +Using the `@Cache` annotation, you can define cache settings on a per type (= class) basis. This is done totally in background, handled by *Morphium* 100% transparently. You just add the annotation to your entities and you're good to go. See [Cache] and [Cache Synchronization] ### Cache Synchronization @@ -461,7 +458,7 @@ By default no cache synchronizer is running. ### Cluster Awareness -*Morphium* is cluster aware in a sense, that it does poll the state of a replicates periodically in order to know what nodes are life and need to be taken into account. (Same does the Java Driver). +*Morphium* is cluster aware in a sense, that it does poll the state of a replicates periodically in order to know what nodes are life and need to be taken into account. (Same does the Java Driver, this information is now moved into the morphium driver implementation, so the double check is not necessary anymore). *Morphium* also has support for clusters *using* it. Like a cluster of tomcats instances. In this case, *Morphium* is able to synchronize the caches of those cluster nodes. @@ -475,6 +472,11 @@ Messaging is 100% multithreaded and thread safe. All operations regarding lists (list updates, writing lists of objects, deleting lists of objects) will be implemented using the new bulk operation available since mongodb 2.6. This gives significant speed boost and adds reliability. +Actually, all method calls to mongo support a list of documents as argument. This means, you can send a list of updates, a list of documents to be inserted, a list of whatever. +The ´BulkOperationContext´ only gathers those requests on the java side together, so that they can be sent in one call, instead of several. + +With Morphium 3.0 an own implementation of this bulk operation context was introduced. + ### Callbacks You can add a number of Listeners to *Morphium* in order to be informed about what happens, or to influence the way things are handled. @@ -484,6 +486,10 @@ You can add a number of Listeners to *Morphium* in order to be informed about wh * ShutdownListener: if the system shuts down, you can be informed using this listener. It's not really *Morphium* specific. * ProfilingListener: will be informed about any read or write access to mongo and how long it took. This is useful if you want to track long requests or index misses. +In addition to that, almost all calls to mongo can be done asynchronously - either by defining that in the @Entity annotation or by defining it directly. + +That means, an `asList()` call on a query object can take an `AsyncCallback` as argument, which then will be called, when the result is ready. (which also means, the `asList` call will return `null`, the result will be passed on in the callback). + ### Support for Aggregation Morphium does have support for Aggregation in mongo. The aggregation Framework was introduced in mongo with V2.6 and is a alternative to MapReduce (which is still used). We implemented support for the new Aggregation framework into mongo. Up until now, there was no request for MapReduce - if you need it, please let me know. @@ -631,7 +637,7 @@ Those validation rules will be enforced upon storing the corresponding object: } -### Plymorphism +### Polymorphism Its possible to have different type of entities stored in one collection. Usually this will only make sense if those entities have some things in common. In an object oriented way: they are derived from one single entity. @@ -1450,4 +1456,4 @@ This logger is built for performance and thread safety. It works find in high lo [1]: http://www.boesebeck.name/wp-content/uploads/2014/09/MorphiumDoku.pdf [2]: http://www.mongodb.org - [3]: http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html \ No newline at end of file + [3]: http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html From 93b1a82ad519e10287ec9b7c778d4fe10c5b585f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 15 Dec 2015 15:03:06 +0100 Subject: [PATCH 4/8] dokumentation updates --- MorphiumDoku.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MorphiumDoku.md b/MorphiumDoku.md index 740fd8b18..8076cc630 100644 --- a/MorphiumDoku.md +++ b/MorphiumDoku.md @@ -13,6 +13,7 @@ html header: cmd = new HashMap<>(); diff --git a/src/de/caluga/morphium/MorphiumConfig.java b/src/de/caluga/morphium/MorphiumConfig.java index 46f57f4db..e11db1710 100644 --- a/src/de/caluga/morphium/MorphiumConfig.java +++ b/src/de/caluga/morphium/MorphiumConfig.java @@ -77,6 +77,8 @@ public class MorphiumConfig { private int maxAutoReconnectTime = 0; private int blockingThreadsMultiplier = 5; + private boolean autoIndexAndCappedCreationOnWrite = true; + @Transient private Class queryClass; @Transient @@ -205,6 +207,14 @@ public MorphiumConfig(String db, int maxConnections, int globalCacheValidTime, i } + public boolean isAutoIndexAndCappedCreationOnWrite() { + return autoIndexAndCappedCreationOnWrite; + } + + public void setAutoIndexAndCappedCreationOnWrite(boolean autoIndexAndCappedCreationOnWrite) { + this.autoIndexAndCappedCreationOnWrite = autoIndexAndCappedCreationOnWrite; + } + public boolean isCheckForNew() { return checkForNew; } diff --git a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java index ebb85b161..e58e8610c 100644 --- a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java +++ b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java @@ -126,7 +126,7 @@ public void run() { if (coll == null) { coll = morphium.getMapper().getCollectionName(type); } - if (!morphium.getDriver().exists(getDbName(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { if (logger.isDebugEnabled()) logger.debug("Collection " + coll + " does not exist - ensuring indices"); createCappedColl(o.getClass()); @@ -346,8 +346,9 @@ public void run() { // BulkWriteOperation bulkWriteOperation = collection.initializeUnorderedBulkOperation(); // BulkRequestContext bulk = morphium.getDriver().createBulkContext(morphium, morphium.getConfig().getDatabase(), collectionName, false, wc); HashMap isNew = new HashMap<>(); - if (!morphium.getDriver().exists(morphium.getConfig().getDatabase(), collectionName)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(morphium.getConfig().getDatabase(), collectionName)) { logger.warn("collection does not exist while storing list - taking first element of list to ensure indices"); + createCappedColl(lst.get(0).getClass()); morphium.ensureIndicesFor((Class) lst.get(0).getClass(), collectionName, callback); } long start = System.currentTimeMillis(); @@ -480,7 +481,7 @@ public void run() { WriteConcern wc = morphium.getWriteConcernForClass(c); String coll = morphium.getMapper().getCollectionName(c); - if (!morphium.getDriver().exists(morphium.getConfig().getDatabase(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(morphium.getConfig().getDatabase(), coll)) { createCappedColl(c); morphium.ensureIndicesFor(c, coll, callback); } @@ -546,12 +547,15 @@ public void run() { } - private void createCappedColl(Class c) { + createCappedColl(c, null); + } + + private void createCappedColl(Class c, String n) { if (logger.isDebugEnabled()) logger.debug("Collection does not exist - ensuring indices / capped status"); Map cmd = new LinkedHashMap<>(); - cmd.put("create", morphium.getMapper().getCollectionName(c)); + cmd.put("create", n != null ? n : morphium.getMapper().getCollectionName(c)); Capped capped = morphium.getARHelper().getAnnotationFromHierarchy(c, Capped.class); if (capped != null) { cmd.put("capped", true); @@ -588,7 +592,7 @@ public void run() { WriteConcern wc = morphium.getWriteConcernForClass(c); String coll = morphium.getMapper().getCollectionName(c); try { - if (!morphium.getDriver().exists(morphium.getConfig().getDatabase(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(morphium.getConfig().getDatabase(), coll)) { if (logger.isDebugEnabled()) logger.debug("Collection does not exist - ensuring indices / capped status"); Map cmd = new LinkedHashMap<>(); @@ -713,7 +717,7 @@ public void run() { long start = System.currentTimeMillis(); try { - if (upsert && !morphium.getDriver().exists(getDbName(), collection)) { + if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), collection)) { morphium.ensureIndicesFor(cls, collection, callback); } @@ -846,7 +850,8 @@ public void run() { collectionName = collection; } - if (!morphium.getDriver().exists(getDbName(), collectionName)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), collectionName)) { + createCappedColl(ent.getClass(), collectionName); morphium.ensureIndicesFor((Class) ent.getClass(), collectionName, callback); } morphium.getDriver().update(getDbName(), collectionName, find, update, false, false, wc); @@ -1038,6 +1043,7 @@ public void run() { long start = System.currentTimeMillis(); try { if (!morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, query, update, false, false, wc); @@ -1109,7 +1115,8 @@ public void run() { long start = System.currentTimeMillis(); try { - if (upsert && !morphium.getDriver().exists(getDbName(), coll)) { + if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor((Class) cls, coll, callback); } WriteConcern wc = morphium.getWriteConcernForClass(cls); @@ -1155,8 +1162,10 @@ public void run() { long start = System.currentTimeMillis(); try { - if (upsert && !morphium.getDriver().exists(getDbName(), coll)) { + if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll, callback); + } WriteConcern wc = morphium.getWriteConcernForClass(cls); morphium.getDriver().update(getDbName(), coll, qobj, update, multiple, upsert, wc); @@ -1248,7 +1257,8 @@ public void run() { WriteConcern wc = morphium.getWriteConcernForClass(cls); long start = System.currentTimeMillis(); try { - if (upsert && !morphium.getDriver().exists(getDbName(), coll)) { + if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor((Class) cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, qobj, update, multiple, upsert, wc); @@ -1361,7 +1371,8 @@ public void run() { long start = System.currentTimeMillis(); try { - if (!morphium.getDriver().exists(getDbName(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, query, update, false, false, wc); @@ -1440,7 +1451,7 @@ public void run() { long start = System.currentTimeMillis(); try { - if (!morphium.getDriver().exists(getDbName(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { morphium.ensureIndicesFor(cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, query, update, false, false, wc); @@ -1623,7 +1634,8 @@ private void pushIt(boolean push, boolean upsert, boolean multiple, Class cls WriteConcern wc = morphium.getWriteConcernForClass(cls); long start = System.currentTimeMillis(); try { - if (!morphium.getDriver().exists(getDbName(), coll) && upsert) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll) && upsert) { + createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll); } morphium.getDriver().update(getDbName(), coll, qobj, update, multiple, upsert, wc); @@ -1715,7 +1727,8 @@ public void run() { WriteConcern wc = morphium.getWriteConcernForClass(cls); try { - if (upsert && !morphium.getDriver().exists(getDbName(), coll)) { + if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor((Class) cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, qobj, update, multiple, upsert, wc); From 3e7b5e7eb26e64c62d7cde9c1213a6354520a7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 12 Jan 2016 08:05:43 +0100 Subject: [PATCH 6/8] missed some places --- src/de/caluga/morphium/writer/MorphiumWriterImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java index e58e8610c..bc34db495 100644 --- a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java +++ b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java @@ -718,6 +718,7 @@ public void run() { try { if (upsert && morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), collection)) { + createCappedColl(cls, collection); morphium.ensureIndicesFor(cls, collection, callback); } @@ -1042,7 +1043,7 @@ public void run() { long start = System.currentTimeMillis(); try { - if (!morphium.getDriver().exists(getDbName(), coll)) { + if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll, callback); } @@ -1452,6 +1453,7 @@ public void run() { try { if (morphium.getConfig().isAutoIndexAndCappedCreationOnWrite() && !morphium.getDriver().exists(getDbName(), coll)) { + createCappedColl(cls, coll); morphium.ensureIndicesFor(cls, coll, callback); } morphium.getDriver().update(getDbName(), coll, query, update, false, false, wc); From c1bf6a716d19fa05da5c736f8e536d51402bb343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 12 Jan 2016 09:03:56 +0100 Subject: [PATCH 7/8] fixed some issues with executors. Exit of VM now works --- src/de/caluga/morphium/Morphium.java | 4 +++ src/de/caluga/morphium/ObjectMapperImpl.java | 2 +- .../morphium/query/QueryFactoryImpl.java | 20 +----------- .../writer/BufferedMorphiumWriterImpl.java | 31 +++++++++++-------- .../morphium/writer/MorphiumWriter.java | 5 +++ .../morphium/writer/MorphiumWriterImpl.java | 4 +++ test/de/caluga/test/mongo/suite/ExitTest.java | 26 ++++++++++++++++ 7 files changed, 59 insertions(+), 33 deletions(-) create mode 100644 test/de/caluga/test/mongo/suite/ExitTest.java diff --git a/src/de/caluga/morphium/Morphium.java b/src/de/caluga/morphium/Morphium.java index 5e40439f7..6281bdafe 100644 --- a/src/de/caluga/morphium/Morphium.java +++ b/src/de/caluga/morphium/Morphium.java @@ -2067,7 +2067,11 @@ public void close() { if (cacheHousekeeper.isAlive()) { cacheHousekeeper.interrupt(); } + rsMonitor.terminate(); + config.getAsyncWriter().close(); + config.getBufferedWriter().close(); + config.getWriter().close(); config.getDb().getMongo().close(); config = null; // MorphiumSingleton.reset(); diff --git a/src/de/caluga/morphium/ObjectMapperImpl.java b/src/de/caluga/morphium/ObjectMapperImpl.java index 556dab70c..28f90cdd7 100644 --- a/src/de/caluga/morphium/ObjectMapperImpl.java +++ b/src/de/caluga/morphium/ObjectMapperImpl.java @@ -488,7 +488,7 @@ public T unmarshall(Class theClass, DBObject o) { if (ret == null) { final Constructor constructor; try { - constructor = reflection.newConstructorForSerialization( + constructor = (Constructor) reflection.newConstructorForSerialization( cls, Object.class.getDeclaredConstructor()); ret = constructor.newInstance(); } catch (Exception e) { diff --git a/src/de/caluga/morphium/query/QueryFactoryImpl.java b/src/de/caluga/morphium/query/QueryFactoryImpl.java index d2efdb3e3..afdd272b2 100644 --- a/src/de/caluga/morphium/query/QueryFactoryImpl.java +++ b/src/de/caluga/morphium/query/QueryFactoryImpl.java @@ -1,11 +1,8 @@ package de.caluga.morphium.query; import de.caluga.morphium.Morphium; -import de.caluga.morphium.ShutdownListener; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; /** * User: Stephan Bösebeck @@ -32,21 +29,6 @@ public QueryFactoryImpl(Class qi) { @Override public ThreadPoolExecutor getExecutor(Morphium m) { - if (executor == null) { - executor = new ThreadPoolExecutor(m.getConfig().getMaxConnections() / 2, (int) (m.getConfig().getMaxConnections() * m.getConfig().getBlockingThreadsMultiplier() * 0.9), - 60L, TimeUnit.SECONDS, - new SynchronousQueue()); - m.addShutdownListener(new ShutdownListener() { - @Override - public void onShutdown(Morphium m) { - try { - executor.shutdownNow(); - } catch (Exception e) { - //swallow - } - } - }); - } return executor; } @@ -66,7 +48,7 @@ public Query createQuery(Morphium m, Class type) { Query q = queryImpl.newInstance(); q.setMorphium(m); q.setType(type); - q.setExecutor(getExecutor(m)); + q.setExecutor(m.getAsyncOperationsThreadPool()); return q; } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); diff --git a/src/de/caluga/morphium/writer/BufferedMorphiumWriterImpl.java b/src/de/caluga/morphium/writer/BufferedMorphiumWriterImpl.java index 75be22836..2339a5097 100644 --- a/src/de/caluga/morphium/writer/BufferedMorphiumWriterImpl.java +++ b/src/de/caluga/morphium/writer/BufferedMorphiumWriterImpl.java @@ -40,6 +40,22 @@ public BufferedMorphiumWriterImpl() { } + public void close() { + running = false; + try { + long start = System.currentTimeMillis(); + while (housekeeping.isAlive()) { + if (System.currentTimeMillis() - start > 1000) { + housekeeping.stop(); + break; + } + Thread.sleep(50); + } + } catch (Exception e) { + //swallow on shutdown + } + } + public boolean isOrderedExecution() { return orderedExecution; } @@ -490,24 +506,13 @@ public void run() { m.addShutdownListener(new ShutdownListener() { @Override public void onShutdown(Morphium m) { - running = false; - try { - long start = System.currentTimeMillis(); - while (housekeeping.isAlive()) { - if (System.currentTimeMillis() - start > 1000) { - housekeeping.stop(); - break; - } - Thread.sleep(50); - } - } catch (Exception e) { - //swallow on shutdown - } + close(); } }); } + @Override public void remove(final List lst, AsyncOperationCallback c) { if (c == null) { diff --git a/src/de/caluga/morphium/writer/MorphiumWriter.java b/src/de/caluga/morphium/writer/MorphiumWriter.java index 1ca096cb7..6fdf30f43 100644 --- a/src/de/caluga/morphium/writer/MorphiumWriter.java +++ b/src/de/caluga/morphium/writer/MorphiumWriter.java @@ -128,5 +128,10 @@ public interface MorphiumWriter { void inc(Query query, Map fieldsToInc, boolean insertIfNotExist, boolean multiple, AsyncOperationCallback callback); + /** + * information about closing of morphium and all connections + */ + void close(); + } diff --git a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java index 41bda7266..29c28a48f 100644 --- a/src/de/caluga/morphium/writer/MorphiumWriterImpl.java +++ b/src/de/caluga/morphium/writer/MorphiumWriterImpl.java @@ -56,6 +56,10 @@ public void setMorphium(Morphium m) { } } + public void close() { + executor.shutdownNow(); + } + /** * @param obj - object to store */ diff --git a/test/de/caluga/test/mongo/suite/ExitTest.java b/test/de/caluga/test/mongo/suite/ExitTest.java new file mode 100644 index 000000000..c134d0026 --- /dev/null +++ b/test/de/caluga/test/mongo/suite/ExitTest.java @@ -0,0 +1,26 @@ +package de.caluga.test.mongo.suite;/** + * Created by stephan on 12.01.16. + */ + +import de.caluga.morphium.Morphium; +import de.caluga.morphium.MorphiumConfig; + +/** + * TODO: Add Documentation here + **/ +public class ExitTest { + + public static void main(String args[]) throws Exception { + // Morphium m=new Morphium("localhost:27017","morphium-test"); + + MorphiumConfig cfg = new MorphiumConfig(); + cfg.setDatabase("morphium-test"); + cfg.setHosts("localhost:27017,localhost:28017,localhost:29017"); + Morphium m = new Morphium(cfg); + System.out.println("Connection opened..."); + + m.createQueryFor(CachedObject.class).countAll(); + m.close(); + System.out.println("All closed"); + } +} From 0c5543a9fe0e1df5e28ff4475d55a27a0881945f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6sebeck?= Date: Tue, 12 Jan 2016 09:12:34 +0100 Subject: [PATCH 8/8] fixed some issues with executors. Exit of VM now works --- src/de/caluga/morphium/Morphium.java | 6 +++++- test/de/caluga/test/mongo/suite/ExitTest.java | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/de/caluga/morphium/Morphium.java b/src/de/caluga/morphium/Morphium.java index 71ca23101..356278cdc 100644 --- a/src/de/caluga/morphium/Morphium.java +++ b/src/de/caluga/morphium/Morphium.java @@ -2090,12 +2090,16 @@ public void close() { if (cacheHousekeeper.isAlive()) { cacheHousekeeper.interrupt(); } + rsMonitor.terminate(); + + config.getAsyncWriter().close(); + config.getBufferedWriter().close(); + config.getWriter().close(); try { getDriver().close(); } catch (MorphiumDriverException e) { e.printStackTrace(); } -// config.getDb().getMongo().close(); config = null; // MorphiumSingleton.reset(); } diff --git a/test/de/caluga/test/mongo/suite/ExitTest.java b/test/de/caluga/test/mongo/suite/ExitTest.java index c134d0026..1429da284 100644 --- a/test/de/caluga/test/mongo/suite/ExitTest.java +++ b/test/de/caluga/test/mongo/suite/ExitTest.java @@ -4,6 +4,7 @@ import de.caluga.morphium.Morphium; import de.caluga.morphium.MorphiumConfig; +import de.caluga.test.mongo.suite.data.CachedObject; /** * TODO: Add Documentation here @@ -15,7 +16,7 @@ public static void main(String args[]) throws Exception { MorphiumConfig cfg = new MorphiumConfig(); cfg.setDatabase("morphium-test"); - cfg.setHosts("localhost:27017,localhost:28017,localhost:29017"); + cfg.setHostSeed("localhost:27017,localhost:27018,localhost:27019"); Morphium m = new Morphium(cfg); System.out.println("Connection opened...");