Every user who works with OrientDB knows that to manipulate records he or she has to create
ODatabaseDocumetTX
an instance first. But there is a wide misunderstanding about the meaning of this object. Many users think that this object may be treated as an abstraction of data which are stored on disk and placed on a server. As a result, they create a single instance of this object per thread, assign it to the class field and use the same object during whole application life. That is “not performance” wise decision. There are several reasons why you should consider using short living database instance acquired from the pool for example from OPartitionedDatabasePool instead
.The most important reason is that during loading of records we put records into the local cache which is based on
WeakHashMap
. We need this cache for 2 reasons:- To avoid
OConcurrentModificationException
in the case of loading of the same record in a call stack. - To speed up graph traversal.
Let's look how
WeakHashMap
works (in OpenJDK at least):- Every put/get/remove method of this
HashMap
calls getTable() method. - Which in turn calls the
expungeStaleEntries()
.
The responsibility of the last method is to remove weak references which are already not accessible.
expungeStaleEntries()
use ReferenceQueue
which was passed during the creation of WeakReference
to detect unreachable references.
The main problem there is mechanics which is used to fill in and pull items from reference queue. When weak reference is becoming a subject of garbage collection special thread which has high priority
java.lang.ref.Reference.ReferenceHandler
put such reference into reference queue. But reference queue itself is guarded by object wide lock !
Let’s put all of this together:
- You have long living
ODatabaseDocumetTX
instance. - You use it to load many short living record objects.
- You have
WeakHashMap
polluted by manyWeakReferences
. - After next GC run
ReferenceHandler
starts to pull and lockReferenceQueue
and as result lockWeakHashMap
objects. - Your threads become frozen for a long time. We know situations when threads were frozen for several seconds !
So the main rule of thumb - never use long living
ODatabaseDocumetTX
instances, use database pool instead. Despite solving the problem described above pool also provides support for nested transactions.
P.S. In 3.0 version we are going to implement WeakHashMap which will be based on Hopscotch hashing algorithm and will not suffer from synchronization problem described above.
No comments :
Post a Comment