[ https://issues.apache.org/jira/browse/PHOENIX-901?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13951476#comment-13951476 ]
Lars Hofhansl commented on PHOENIX-901: --------------------------------------- So looking at all the complexity here, I think is far better to turn connectionQueryServicesMap into a normal map, not synchronizing in the init() method, and just add synchronized to getConnectionQueryServices (maybe add a synchronized(this) inside to let the first few instruction run unsynchronized). Here's why: # The main problem is that we need to make creation of the object and placement of the object into map atomic if initialization of the object is potentially non-trivial (as is the case here). # If multiple threads come in the first time, we want them to wait anyway, unless one succeeds to initialize the connection # Once the connection is initialized it is just a lookup in a map. So each thread would leave the synchronized section after a couple of nanoseconds. # a volatile is roughly as expensive as an uncontended synchronized (the cost is setting up the memory fences) # getConnectionQueryServices won't be called more than once per query (correct?), so it's not on the critical path # It's easy to follow and easy to understand > Ensure ConnectionQueryServices only initialized once > ---------------------------------------------------- > > Key: PHOENIX-901 > URL: https://issues.apache.org/jira/browse/PHOENIX-901 > Project: Phoenix > Issue Type: Bug > Reporter: James Taylor > Assignee: James Taylor > Fix For: 3.0.0, 4.0.0 > > Attachments: phoenix.patch, phoenix_2.patch, phoenix_3.patch, > phoenix_4.patch > > > We should call connectionQueryServices#init in the else block of this code: > {code} > @Override > protected ConnectionQueryServices getConnectionQueryServices(String url, > Properties info) throws SQLException { > checkClosed(); > ConnectionInfo connInfo = ConnectionInfo.create(url); > ConnectionInfo normalizedConnInfo = > connInfo.normalize(getQueryServices().getProps()); > ConnectionQueryServices connectionQueryServices = > connectionQueryServicesMap.get(normalizedConnInfo); > if (connectionQueryServices == null) { > if (normalizedConnInfo.isConnectionless()) { > connectionQueryServices = new > ConnectionlessQueryServicesImpl(getQueryServices()); > } else { > connectionQueryServices = new > ConnectionQueryServicesImpl(getQueryServices(), normalizedConnInfo); > } > connectionQueryServices.init(url, info); > ConnectionQueryServices prevValue = > connectionQueryServicesMap.putIfAbsent(normalizedConnInfo, > connectionQueryServices); > if (prevValue != null) { > connectionQueryServices = prevValue; > } > } > return connectionQueryServices; > } > {code} > like this instead: > {code} > @Override > protected ConnectionQueryServices getConnectionQueryServices(String url, > Properties info) throws SQLException { > checkClosed(); > ConnectionInfo connInfo = ConnectionInfo.create(url); > ConnectionInfo normalizedConnInfo = > connInfo.normalize(getQueryServices().getProps()); > ConnectionQueryServices connectionQueryServices = > connectionQueryServicesMap.get(normalizedConnInfo); > if (connectionQueryServices == null) { > if (normalizedConnInfo.isConnectionless()) { > connectionQueryServices = new > ConnectionlessQueryServicesImpl(getQueryServices()); > } else { > connectionQueryServices = new > ConnectionQueryServicesImpl(getQueryServices(), normalizedConnInfo); > } > ConnectionQueryServices prevValue = > connectionQueryServicesMap.putIfAbsent(normalizedConnInfo, > connectionQueryServices); > if (prevValue != null) { > connectionQueryServices = prevValue; > } else { > connectionQueryServices.init(url, info); > } > } > return connectionQueryServices; > } > {code} > This has the potential to open multiple HConnections, but it's unclear if > this causes harm, as the same, original ConnectionQueryService is returned > and used. -- This message was sent by Atlassian JIRA (v6.2#6252)