Different methods may synchronize on different subsets of the namenode's data, but it is not necessary. The global FSNamesystem lock will still be there and it will provide consistency across data structures. The other locks are per data structure. I want to keep the lock hierarchy very very simple with only two levels. My aim is to design a scheme that has very low risk of deadlocks and optimize only those methods that are really necessary. The other portions of the file system will still be protected by the global FSNamesystem lock. The lock hierarchy has only two levels:
1. First acquire the global FSNasmesystem lock
2, Then acquire any of the other data structure lock. These locks are at the same lock level, so one cannot acquire a lock while holding another. For example, one cannot acquire the lock on neededReplications while holding the lock on blocksMap.
For example, there will be a lock for pendingCreates. Insertion and deletion of a file and its blocks into pendingCreates will be protected by the pendingCreates lock. Now, getAdditionalBlock() does not need to keep the global FSNamesystem lock. Similarly, addStoredBlock adds a block to the blocksMap. This will be protected by the blocksMap lock. Thus addStoredBlock does not need to hold the FSNamesystem lock. This will make addStoredBlock and getAdditionalBlock() execute in parallel.
Both pendingCreates and blocksMap are backed by a HashMap. I plan on changing them to ConcurrentHashMap and measure performance. This will make multiple instances of addStoredBlock() run in parallel.
We have done a first pass of performance improvements to both addStoredMap and getAdditionalBlock. The profiler clearly shows that the time to execute the code of these methods was very small, however the lock wait times were extremely high.
Please let me know if this sounds reasonable.