Every user who works with OrientDB knows that to manipulate records he or she has to create
ODatabaseDocumetTXan 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
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
OConcurrentModificationExceptionin the case of loading of the same record in a call stack.
- To speed up graph traversal.
Let's look how
WeakHashMapworks (in OpenJDK at least):
- Every put/get/remove method of this
HashMapcalls getTable() method.
- Which in turn calls the
The responsibility of the last method is to remove weak references which are already not accessible.
ReferenceQueuewhich was passed during the creation of
WeakReferenceto 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.ReferenceHandlerput 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
- You use it to load many short living record objects.
- You have
WeakHashMappolluted by many
- After next GC run
ReferenceHandlerstarts to pull and lock
ReferenceQueueand as result lock
- 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
ODatabaseDocumetTXinstances, 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.