From f0d21710b5a59226fe2f45a989d8134d9cae996a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 21 Mar 2016 10:53:28 +1300 Subject: Make data manager thread safe (fix #1808) --- src/org/traccar/database/DataManager.java | 113 +++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 19 deletions(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index d2da4e701..419d5043c 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -26,6 +26,8 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.naming.InitialContext; import javax.sql.DataSource; @@ -59,10 +61,12 @@ public class DataManager implements IdentityManager { private final long dataRefreshDelay; + private final ReadWriteLock devicesLock = new ReentrantReadWriteLock(); private final Map devicesById = new HashMap<>(); private final Map devicesByUniqueId = new HashMap<>(); private long devicesLastUpdate; + private final ReadWriteLock groupsLock = new ReentrantReadWriteLock(); private final Map groupsById = new HashMap<>(); private long groupsLastUpdate; @@ -120,51 +124,122 @@ public class DataManager implements IdentityManager { } private void updateDeviceCache(boolean force) throws SQLException { - if (System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay || force) { - devicesById.clear(); - devicesByUniqueId.clear(); - for (Device device : getAllDevices()) { - devicesById.put(device.getId(), device); - devicesByUniqueId.put(device.getUniqueId(), device); + boolean needWrite; + devicesLock.readLock().lock(); + try { + needWrite = force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay; + } finally { + devicesLock.readLock().unlock(); + } + + if (needWrite) { + devicesLock.writeLock().lock(); + try { + if (force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay) { + devicesById.clear(); + devicesByUniqueId.clear(); + for (Device device : getAllDevices()) { + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); + } + devicesLastUpdate = System.currentTimeMillis(); + } + } finally { + devicesLock.writeLock().unlock(); } - devicesLastUpdate = System.currentTimeMillis(); } } @Override public Device getDeviceById(long id) { + boolean forceUpdate; + devicesLock.readLock().lock(); + try { + forceUpdate = !devicesById.containsKey(id); + } finally { + devicesLock.readLock().unlock(); + } + try { - updateDeviceCache(!devicesById.containsKey(id)); + updateDeviceCache(forceUpdate); } catch (SQLException e) { Log.warning(e); } - return devicesById.get(id); + + devicesLock.readLock().lock(); + try { + return devicesById.get(id); + } finally { + devicesLock.readLock().unlock(); + } } @Override public Device getDeviceByUniqueId(String uniqueId) throws SQLException { - updateDeviceCache( - !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown")); - return devicesByUniqueId.get(uniqueId); + boolean forceUpdate; + devicesLock.readLock().lock(); + try { + forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); + } finally { + devicesLock.readLock().unlock(); + } + + updateDeviceCache(forceUpdate); + + devicesLock.readLock().lock(); + try { + return devicesByUniqueId.get(uniqueId); + } finally { + devicesLock.readLock().unlock(); + } } private void updateGroupCache(boolean force) throws SQLException { - if (System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay || force) { - groupsById.clear(); - for (Group group : getAllGroups()) { - groupsById.put(group.getId(), group); + boolean needWrite; + groupsLock.readLock().lock(); + try { + needWrite = force || System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay; + } finally { + groupsLock.readLock().unlock(); + } + + if (needWrite) { + groupsLock.writeLock().lock(); + try { + if (force || System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay) { + groupsById.clear(); + for (Group group : getAllGroups()) { + groupsById.put(group.getId(), group); + } + groupsLastUpdate = System.currentTimeMillis(); + } + } finally { + groupsLock.writeLock().unlock(); } - groupsLastUpdate = System.currentTimeMillis(); } } public Group getGroupById(long id) { + boolean forceUpdate; + groupsLock.readLock().lock(); try { - updateGroupCache(!groupsById.containsKey(id)); + forceUpdate = !groupsById.containsKey(id); + } finally { + groupsLock.readLock().unlock(); + } + + try { + updateGroupCache(forceUpdate); } catch (SQLException e) { Log.warning(e); } - return groupsById.get(id); + + groupsLock.readLock().lock(); + try { + return groupsById.get(id); + } finally { + groupsLock.readLock().unlock(); + } } private String getQuery(String key) { -- cgit v1.2.3