From b91d1b41343a1d3d8625c1dc42c9c7d2244fb903 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Tue, 19 Jul 2016 16:54:13 +0500 Subject: Split locks in GeofenceManager and try to avoid crosslocks with devices. --- src/org/traccar/database/GeofenceManager.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/org/traccar/database') diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java index dc31172b9..2994920d9 100644 --- a/src/org/traccar/database/GeofenceManager.java +++ b/src/org/traccar/database/GeofenceManager.java @@ -155,25 +155,34 @@ public class GeofenceManager { public final void refresh() { if (dataManager != null) { try { + + Collection databaseGroupGeofences = dataManager.getGroupGeofences(); groupGeofencesLock.writeLock().lock(); - deviceGeofencesLock.writeLock().lock(); try { groupGeofences.clear(); - for (GroupGeofence groupGeofence : dataManager.getGroupGeofences()) { + for (GroupGeofence groupGeofence : databaseGroupGeofences) { getGroupGeofences(groupGeofence.getGroupId()).add(groupGeofence.getGeofenceId()); } + } finally { + groupGeofencesLock.writeLock().unlock(); + } + Collection databaseDeviceGeofences = dataManager.getDeviceGeofences(); + Collection allDevices = Context.getDeviceManager().getAllDevices(); + + deviceGeofencesLock.writeLock().lock(); + try { deviceGeofences.clear(); deviceGeofencesWithGroups.clear(); - for (DeviceGeofence deviceGeofence : dataManager.getDeviceGeofences()) { + for (DeviceGeofence deviceGeofence : databaseDeviceGeofences) { getDeviceGeofences(deviceGeofences, deviceGeofence.getDeviceId()) .add(deviceGeofence.getGeofenceId()); getDeviceGeofences(deviceGeofencesWithGroups, deviceGeofence.getDeviceId()) .add(deviceGeofence.getGeofenceId()); } - for (Device device : Context.getDeviceManager().getAllDevices()) { + for (Device device : allDevices) { long groupId = device.getGroupId(); while (groupId != 0) { getDeviceGeofences(deviceGeofencesWithGroups, @@ -204,7 +213,6 @@ public class GeofenceManager { } } finally { - groupGeofencesLock.writeLock().unlock(); deviceGeofencesLock.writeLock().unlock(); } -- cgit v1.2.3 From 6ef76c9e22ada4ed5d89d0a3bd43d759b56bebe0 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Tue, 19 Jul 2016 17:03:00 +0500 Subject: Missed groupGeofences read lock --- src/org/traccar/database/GeofenceManager.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/org/traccar/database') diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java index 2994920d9..930008082 100644 --- a/src/org/traccar/database/GeofenceManager.java +++ b/src/org/traccar/database/GeofenceManager.java @@ -170,6 +170,7 @@ public class GeofenceManager { Collection databaseDeviceGeofences = dataManager.getDeviceGeofences(); Collection allDevices = Context.getDeviceManager().getAllDevices(); + groupGeofencesLock.readLock().lock(); deviceGeofencesLock.writeLock().lock(); try { deviceGeofences.clear(); @@ -214,6 +215,7 @@ public class GeofenceManager { } finally { deviceGeofencesLock.writeLock().unlock(); + groupGeofencesLock.readLock().unlock(); } } catch (SQLException error) { -- cgit v1.2.3 From 32a7fe7eb22d435906b65f91c37751ece4fea828 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Wed, 20 Jul 2016 10:45:52 +0500 Subject: - Move groups related actions to DeviceManager - Removed cache updates from getXxxxById --- .checkstyle | 10 ++ src/org/traccar/api/resource/GroupResource.java | 10 +- src/org/traccar/database/DataManager.java | 94 --------------- src/org/traccar/database/DeviceManager.java | 140 ++++++++++++++++++++--- src/org/traccar/database/GeofenceManager.java | 4 +- src/org/traccar/database/PermissionsManager.java | 3 +- 6 files changed, 144 insertions(+), 117 deletions(-) create mode 100644 .checkstyle (limited to 'src/org/traccar/database') diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 000000000..0b4b1b908 --- /dev/null +++ b/.checkstyle @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/org/traccar/api/resource/GroupResource.java b/src/org/traccar/api/resource/GroupResource.java index 957f39ebe..eec28e325 100644 --- a/src/org/traccar/api/resource/GroupResource.java +++ b/src/org/traccar/api/resource/GroupResource.java @@ -43,20 +43,20 @@ public class GroupResource extends BaseResource { @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException { if (all) { Context.getPermissionsManager().checkAdmin(getUserId()); - return Context.getDataManager().getAllGroups(); + return Context.getDeviceManager().getAllGroups(); } else { if (userId == 0) { userId = getUserId(); } Context.getPermissionsManager().checkUser(getUserId(), userId); - return Context.getDataManager().getGroups(userId); + return Context.getDeviceManager().getGroups(userId); } } @POST public Response add(Group entity) throws SQLException { Context.getPermissionsManager().checkReadonly(getUserId()); - Context.getDataManager().addGroup(entity); + Context.getDeviceManager().addGroup(entity); Context.getDataManager().linkGroup(getUserId(), entity.getId()); Context.getPermissionsManager().refresh(); if (Context.getGeofenceManager() != null) { @@ -70,7 +70,7 @@ public class GroupResource extends BaseResource { public Response update(@PathParam("id") long id, Group entity) throws SQLException { Context.getPermissionsManager().checkReadonly(getUserId()); Context.getPermissionsManager().checkGroup(getUserId(), id); - Context.getDataManager().updateGroup(entity); + Context.getDeviceManager().updateGroup(entity); if (Context.getGeofenceManager() != null) { Context.getGeofenceManager().refresh(); } @@ -82,7 +82,7 @@ public class GroupResource extends BaseResource { public Response remove(@PathParam("id") long id) throws SQLException { Context.getPermissionsManager().checkReadonly(getUserId()); Context.getPermissionsManager().checkGroup(getUserId(), id); - Context.getDataManager().removeGroup(id); + Context.getDeviceManager().removeGroup(id); Context.getPermissionsManager().refresh(); if (Context.getGeofenceManager() != null) { Context.getGeofenceManager().refresh(); diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 0aecaf2e7..be77a3d36 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -20,16 +20,9 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.sql.SQLException; -import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.naming.InitialContext; import javax.sql.DataSource; @@ -43,7 +36,6 @@ import liquibase.resource.FileSystemResourceAccessor; import liquibase.resource.ResourceAccessor; import org.traccar.Config; -import org.traccar.Context; import org.traccar.helper.Log; import org.traccar.model.Device; import org.traccar.model.DevicePermission; @@ -64,25 +56,15 @@ import com.zaxxer.hikari.HikariDataSource; public class DataManager { - public static final long DEFAULT_REFRESH_DELAY = 300; - private final Config config; private DataSource dataSource; - private final long dataRefreshDelay; - - private final ReadWriteLock groupsLock = new ReentrantReadWriteLock(); - private final Map groupsById = new HashMap<>(); - private long groupsLastUpdate; - public DataManager(Config config) throws Exception { this.config = config; initDatabase(); initDatabaseSchema(); - - dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; } public DataSource getDataSource() { @@ -131,54 +113,6 @@ public class DataManager { } } - private void updateGroupCache(boolean force) throws SQLException { - 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(); - } - } - } - - public Group getGroupById(long id) { - boolean forceUpdate; - groupsLock.readLock().lock(); - try { - forceUpdate = !groupsById.containsKey(id); - } finally { - groupsLock.readLock().unlock(); - } - - try { - updateGroupCache(forceUpdate); - } catch (SQLException e) { - Log.warning(e); - } - - groupsLock.readLock().lock(); - try { - return groupsById.get(id); - } finally { - groupsLock.readLock().unlock(); - } - } - private String getQuery(String key) { String query = config.getString(key); if (query == null) { @@ -311,44 +245,16 @@ public class DataManager { .executeQuery(Group.class); } - public Collection getGroups(long userId) throws SQLException { - Collection groups = new ArrayList<>(); - for (long id : Context.getPermissionsManager().getGroupPermissions(userId)) { - groups.add(getGroupById(id)); - } - return groups; - } - - private void checkGroupCycles(Group group) { - groupsLock.readLock().lock(); - try { - Set groups = new HashSet<>(); - while (group != null) { - if (groups.contains(group.getId())) { - throw new IllegalArgumentException("Cycle in group hierarchy"); - } - groups.add(group.getId()); - group = groupsById.get(group.getGroupId()); - } - } finally { - groupsLock.readLock().unlock(); - } - } - public void addGroup(Group group) throws SQLException { - checkGroupCycles(group); group.setId(QueryBuilder.create(dataSource, getQuery("database.insertGroup"), true) .setObject(group) .executeUpdate()); - updateGroupCache(true); } public void updateGroup(Group group) throws SQLException { - checkGroupCycles(group); QueryBuilder.create(dataSource, getQuery("database.updateGroup")) .setObject(group) .executeUpdate(); - updateGroupCache(true); } public void removeGroup(long groupId) throws SQLException { diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index 173e68062..b6cb8c65f 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -19,9 +19,11 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -30,10 +32,13 @@ import org.traccar.Config; import org.traccar.Context; import org.traccar.helper.Log; import org.traccar.model.Device; +import org.traccar.model.Group; import org.traccar.model.Position; public class DeviceManager implements IdentityManager { + public static final long DEFAULT_REFRESH_DELAY = 300; + private final Config config; private final DataManager dataManager; private final long dataRefreshDelay; @@ -43,14 +48,20 @@ public class DeviceManager implements IdentityManager { private final Map devicesByUniqueId = new HashMap<>(); private long devicesLastUpdate; + private final ReadWriteLock groupsLock = new ReentrantReadWriteLock(); + private final Map groupsById = new HashMap<>(); + private long groupsLastUpdate; + private final Map positions = new ConcurrentHashMap<>(); public DeviceManager(DataManager dataManager) { this.dataManager = dataManager; this.config = Context.getConfig(); - dataRefreshDelay = config.getLong("database.refreshDelay", DataManager.DEFAULT_REFRESH_DELAY) * 1000; + dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; if (dataManager != null) { try { + updateDeviceCache(true); + updateGroupCache(true); for (Position position : dataManager.getLatestPositions()) { positions.put(position.getDeviceId(), position); } @@ -96,20 +107,6 @@ public class DeviceManager implements IdentityManager { @Override public Device getDeviceById(long id) { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = !devicesById.containsKey(id); - } finally { - devicesLock.readLock().unlock(); - } - - try { - updateDeviceCache(forceUpdate); - } catch (SQLException e) { - Log.warning(e); - } - devicesLock.readLock().lock(); try { return devicesById.get(id); @@ -273,4 +270,117 @@ public class DeviceManager implements IdentityManager { return result; } + + private void updateGroupCache(boolean force) throws SQLException { + 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 : dataManager.getAllGroups()) { + groupsById.put(group.getId(), group); + } + groupsLastUpdate = System.currentTimeMillis(); + } + } finally { + groupsLock.writeLock().unlock(); + } + } + } + + public Group getGroupById(long id) { + groupsLock.readLock().lock(); + try { + return groupsById.get(id); + } finally { + groupsLock.readLock().unlock(); + } + } + + public Collection getAllGroups() { + boolean forceUpdate; + groupsLock.readLock().lock(); + try { + forceUpdate = groupsById.isEmpty(); + } finally { + groupsLock.readLock().unlock(); + } + + try { + updateGroupCache(forceUpdate); + } catch (SQLException e) { + Log.warning(e); + } + + groupsLock.readLock().lock(); + try { + return groupsById.values(); + } finally { + groupsLock.readLock().unlock(); + } + } + + public Collection getGroups(long userId) throws SQLException { + Collection groups = new ArrayList<>(); + for (long id : Context.getPermissionsManager().getGroupPermissions(userId)) { + groups.add(getGroupById(id)); + } + return groups; + } + + private void checkGroupCycles(Group group) { + groupsLock.readLock().lock(); + try { + Set groups = new HashSet<>(); + while (group != null) { + if (groups.contains(group.getId())) { + throw new IllegalArgumentException("Cycle in group hierarchy"); + } + groups.add(group.getId()); + group = groupsById.get(group.getGroupId()); + } + } finally { + groupsLock.readLock().unlock(); + } + } + + public void addGroup(Group group) throws SQLException { + checkGroupCycles(group); + dataManager.addGroup(group); + groupsLock.writeLock().lock(); + try { + groupsById.put(group.getId(), group); + } finally { + groupsLock.writeLock().unlock(); + } + } + + public void updateGroup(Group group) throws SQLException { + checkGroupCycles(group); + dataManager.updateGroup(group); + groupsLock.writeLock().lock(); + try { + groupsById.put(group.getId(), group); + } finally { + groupsLock.writeLock().unlock(); + } + } + + public void removeGroup(long groupId) throws SQLException { + dataManager.removeGroup(groupId); + groupsLock.writeLock().lock(); + try { + groupsById.remove(groupId); + } finally { + groupsLock.writeLock().unlock(); + } + } } diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java index 930008082..74dff70f4 100644 --- a/src/org/traccar/database/GeofenceManager.java +++ b/src/org/traccar/database/GeofenceManager.java @@ -188,8 +188,8 @@ public class GeofenceManager { while (groupId != 0) { getDeviceGeofences(deviceGeofencesWithGroups, device.getId()).addAll(getGroupGeofences(groupId)); - if (dataManager.getGroupById(groupId) != null) { - groupId = dataManager.getGroupById(groupId).getGroupId(); + if (Context.getDeviceManager().getGroupById(groupId) != null) { + groupId = Context.getDeviceManager().getGroupById(groupId).getGroupId(); } else { groupId = 0; } diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 5a15375b4..d786dcc4e 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -78,7 +78,8 @@ public class PermissionsManager { users.put(user.getId(), user); } - GroupTree groupTree = new GroupTree(dataManager.getAllGroups(), Context.getDeviceManager().getAllDevices()); + GroupTree groupTree = new GroupTree(Context.getDeviceManager().getAllGroups(), + Context.getDeviceManager().getAllDevices()); for (GroupPermission permission : dataManager.getGroupPermissions()) { Set userGroupPermissions = getGroupPermissions(permission.getUserId()); Set userDevicePermissions = getDevicePermissions(permission.getUserId()); -- cgit v1.2.3 From 56784bd167ddf0bbc124269519b7a93b346bd5cc Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Wed, 20 Jul 2016 15:57:15 +0500 Subject: Change order cache initialization --- .checkstyle | 10 ---------- .gitignore | 1 + src/org/traccar/database/DeviceManager.java | 2 +- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 .checkstyle (limited to 'src/org/traccar/database') diff --git a/.checkstyle b/.checkstyle deleted file mode 100644 index 0b4b1b908..000000000 --- a/.checkstyle +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.gitignore b/.gitignore index 4bb6eefb9..00818a38a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ nbactions.xml .idea *.iml .DS_Store +.checkstyle diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index b6cb8c65f..43d83d078 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -60,8 +60,8 @@ public class DeviceManager implements IdentityManager { dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; if (dataManager != null) { try { - updateDeviceCache(true); updateGroupCache(true); + updateDeviceCache(true); for (Position position : dataManager.getLatestPositions()) { positions.put(position.getDeviceId(), position); } -- cgit v1.2.3 From b4e0833b1b180f40b132e60ee49d897d409bc000 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Thu, 21 Jul 2016 09:56:41 +0500 Subject: Migrate from ReentrantReadWriteLocks to ConcurrentHashMaps in DeviceManager UpdateCahces incrementally --- src/org/traccar/database/DeviceManager.java | 286 +++++++++++----------------- 1 file changed, 106 insertions(+), 180 deletions(-) (limited to 'src/org/traccar/database') diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index 43d83d078..916e7fe67 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -18,15 +18,13 @@ package org.traccar.database; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.atomic.AtomicLong; import org.traccar.Config; import org.traccar.Context; @@ -43,14 +41,12 @@ public class DeviceManager implements IdentityManager { private final DataManager dataManager; 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 Map devicesById; + private Map devicesByUniqueId; + private AtomicLong devicesLastUpdate = new AtomicLong(0); - private final ReadWriteLock groupsLock = new ReentrantReadWriteLock(); - private final Map groupsById = new HashMap<>(); - private long groupsLastUpdate; + private Map groupsById; + private AtomicLong groupsLastUpdate = new AtomicLong(0); private final Map positions = new ConcurrentHashMap<>(); @@ -72,77 +68,76 @@ public class DeviceManager implements IdentityManager { } private void updateDeviceCache(boolean force) throws SQLException { - boolean needWrite; - devicesLock.readLock().lock(); - try { - needWrite = force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay; - } finally { - devicesLock.readLock().unlock(); - } - + boolean needWrite = force || System.currentTimeMillis() - devicesLastUpdate.get() > dataRefreshDelay; if (needWrite) { - devicesLock.writeLock().lock(); - try { - if (force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay) { - devicesById.clear(); - devicesByUniqueId.clear(); - GeofenceManager geofenceManager = Context.getGeofenceManager(); - for (Device device : dataManager.getAllDevices()) { - devicesById.put(device.getId(), device); - devicesByUniqueId.put(device.getUniqueId(), device); - if (geofenceManager != null) { - Position lastPosition = getLastPosition(device.getId()); - if (lastPosition != null) { - device.setGeofenceIds(geofenceManager.getCurrentDeviceGeofences(lastPosition)); - } + GeofenceManager geofenceManager = Context.getGeofenceManager(); + Collection databaseDevices = dataManager.getAllDevices(); + if (devicesById == null) { + devicesById = new ConcurrentHashMap<>(databaseDevices.size()); + } + if (devicesByUniqueId == null) { + devicesByUniqueId = new ConcurrentHashMap<>(databaseDevices.size()); + } + Set databaseDevicesIds = new HashSet<>(); + Set databaseDevicesUniqIds = new HashSet<>(); + for (Device device : databaseDevices) { + databaseDevicesIds.add(device.getId()); + databaseDevicesUniqIds.add(device.getUniqueId()); + if (devicesById.containsKey(device.getId())) { + Device cachedDevice = devicesById.get(device.getId()); + cachedDevice.setName(device.getName()); + cachedDevice.setGroupId(device.getGroupId()); + cachedDevice.setAttributes(device.getAttributes()); + if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) { + devicesByUniqueId.remove(cachedDevice.getUniqueId()); + devicesByUniqueId.put(device.getUniqueId(), cachedDevice); + } + cachedDevice.setUniqueId(device.getUniqueId()); + } else { + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); + if (geofenceManager != null) { + Position lastPosition = getLastPosition(device.getId()); + if (lastPosition != null) { + device.setGeofenceIds(geofenceManager.getCurrentDeviceGeofences(lastPosition)); } } - devicesLastUpdate = System.currentTimeMillis(); + device.setStatus(Device.STATUS_OFFLINE); + device.setMotion(Device.STATUS_STOPPED); } - } finally { - devicesLock.writeLock().unlock(); } + for (Long cachedDeviceId : devicesById.keySet()) { + if (!databaseDevicesIds.contains(cachedDeviceId)) { + devicesById.remove(cachedDeviceId); + } + } + for (String cachedDeviceUniqId : devicesByUniqueId.keySet()) { + if (!databaseDevicesUniqIds.contains(cachedDeviceUniqId)) { + devicesByUniqueId.remove(cachedDeviceUniqId); + } + } + databaseDevicesIds.clear(); + databaseDevicesUniqIds.clear(); + devicesLastUpdate.set(System.currentTimeMillis()); } } @Override public Device getDeviceById(long id) { - devicesLock.readLock().lock(); - try { - return devicesById.get(id); - } finally { - devicesLock.readLock().unlock(); - } + return devicesById.get(id); } @Override public Device getDeviceByUniqueId(String uniqueId) throws SQLException { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); - } finally { - devicesLock.readLock().unlock(); - } + boolean forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); updateDeviceCache(forceUpdate); - devicesLock.readLock().lock(); - try { - return devicesByUniqueId.get(uniqueId); - } finally { - devicesLock.readLock().unlock(); - } + return devicesByUniqueId.get(uniqueId); } public Collection getAllDevices() { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = devicesById.isEmpty(); - } finally { - devicesLock.readLock().unlock(); - } + boolean forceUpdate = devicesById.isEmpty(); try { updateDeviceCache(forceUpdate); @@ -150,23 +145,13 @@ public class DeviceManager implements IdentityManager { Log.warning(e); } - devicesLock.readLock().lock(); - try { - return devicesById.values(); - } finally { - devicesLock.readLock().unlock(); - } + return devicesById.values(); } public Collection getDevices(long userId) throws SQLException { Collection devices = new ArrayList<>(); - devicesLock.readLock().lock(); - try { - for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) { - devices.add(devicesById.get(id)); - } - } finally { - devicesLock.readLock().unlock(); + for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) { + devices.add(devicesById.get(id)); } return devices; } @@ -174,56 +159,34 @@ public class DeviceManager implements IdentityManager { public void addDevice(Device device) throws SQLException { dataManager.addDevice(device); - devicesLock.writeLock().lock(); - try { - devicesById.put(device.getId(), device); - devicesByUniqueId.put(device.getUniqueId(), device); - } finally { - devicesLock.writeLock().unlock(); - } + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); } public void updateDevice(Device device) throws SQLException { dataManager.updateDevice(device); - devicesLock.writeLock().lock(); - try { - devicesById.put(device.getId(), device); - devicesByUniqueId.put(device.getUniqueId(), device); - } finally { - devicesLock.writeLock().unlock(); - } + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); } public void updateDeviceStatus(Device device) throws SQLException { dataManager.updateDeviceStatus(device); - - devicesLock.writeLock().lock(); - try { - if (devicesById.containsKey(device.getId())) { - Device cachedDevice = devicesById.get(device.getId()); - cachedDevice.setStatus(device.getStatus()); - cachedDevice.setMotion(device.getMotion()); - } - } finally { - devicesLock.writeLock().unlock(); + if (devicesById.containsKey(device.getId())) { + Device cachedDevice = devicesById.get(device.getId()); + cachedDevice.setStatus(device.getStatus()); + cachedDevice.setMotion(device.getMotion()); } } public void removeDevice(long deviceId) throws SQLException { dataManager.removeDevice(deviceId); - devicesLock.writeLock().lock(); - try { - if (devicesById.containsKey(deviceId)) { - String deviceUniqueId = devicesById.get(deviceId).getUniqueId(); - devicesById.remove(deviceId); - devicesByUniqueId.remove(deviceUniqueId); - } - } finally { - devicesLock.writeLock().unlock(); + if (devicesById.containsKey(deviceId)) { + String deviceUniqueId = devicesById.get(deviceId).getUniqueId(); + devicesById.remove(deviceId); + devicesByUniqueId.remove(deviceUniqueId); } - positions.remove(deviceId); } @@ -234,13 +197,8 @@ public class DeviceManager implements IdentityManager { dataManager.updateLatestPosition(position); - devicesLock.writeLock().lock(); - try { - if (devicesById.containsKey(position.getDeviceId())) { - devicesById.get(position.getDeviceId()).setPositionId(position.getId()); - } - } finally { - devicesLock.writeLock().unlock(); + if (devicesById.containsKey(position.getDeviceId())) { + devicesById.get(position.getDeviceId()).setPositionId(position.getId()); } positions.put(position.getDeviceId(), position); @@ -272,47 +230,40 @@ public class DeviceManager implements IdentityManager { } private void updateGroupCache(boolean force) throws SQLException { - boolean needWrite; - groupsLock.readLock().lock(); - try { - needWrite = force || System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay; - } finally { - groupsLock.readLock().unlock(); - } + boolean needWrite = force || System.currentTimeMillis() - groupsLastUpdate.get() > dataRefreshDelay; if (needWrite) { - groupsLock.writeLock().lock(); - try { - if (force || System.currentTimeMillis() - groupsLastUpdate > dataRefreshDelay) { - groupsById.clear(); - for (Group group : dataManager.getAllGroups()) { - groupsById.put(group.getId(), group); - } - groupsLastUpdate = System.currentTimeMillis(); + Collection databaseGroups = dataManager.getAllGroups(); + if (groupsById == null) { + groupsById = new ConcurrentHashMap<>(databaseGroups.size()); + } + Set databaseGroupsIds = new HashSet<>(); + for (Group group : databaseGroups) { + databaseGroupsIds.add(group.getId()); + if (groupsById.containsKey(group.getId())) { + Group cachedGroup = groupsById.get(group.getId()); + cachedGroup.setName(group.getName()); + cachedGroup.setGroupId(group.getGroupId()); + } else { + groupsById.put(group.getId(), group); + } + } + for (Long cachedGroupId : groupsById.keySet()) { + if (!databaseGroupsIds.contains(cachedGroupId)) { + devicesById.remove(cachedGroupId); } - } finally { - groupsLock.writeLock().unlock(); } + databaseGroupsIds.clear(); + groupsLastUpdate.set(System.currentTimeMillis()); } } public Group getGroupById(long id) { - groupsLock.readLock().lock(); - try { - return groupsById.get(id); - } finally { - groupsLock.readLock().unlock(); - } + return groupsById.get(id); } public Collection getAllGroups() { - boolean forceUpdate; - groupsLock.readLock().lock(); - try { - forceUpdate = groupsById.isEmpty(); - } finally { - groupsLock.readLock().unlock(); - } + boolean forceUpdate = groupsById.isEmpty(); try { updateGroupCache(forceUpdate); @@ -320,12 +271,7 @@ public class DeviceManager implements IdentityManager { Log.warning(e); } - groupsLock.readLock().lock(); - try { - return groupsById.values(); - } finally { - groupsLock.readLock().unlock(); - } + return groupsById.values(); } public Collection getGroups(long userId) throws SQLException { @@ -337,50 +283,30 @@ public class DeviceManager implements IdentityManager { } private void checkGroupCycles(Group group) { - groupsLock.readLock().lock(); - try { - Set groups = new HashSet<>(); - while (group != null) { - if (groups.contains(group.getId())) { - throw new IllegalArgumentException("Cycle in group hierarchy"); - } - groups.add(group.getId()); - group = groupsById.get(group.getGroupId()); + Set groups = new HashSet<>(); + while (group != null) { + if (groups.contains(group.getId())) { + throw new IllegalArgumentException("Cycle in group hierarchy"); } - } finally { - groupsLock.readLock().unlock(); + groups.add(group.getId()); + group = groupsById.get(group.getGroupId()); } } public void addGroup(Group group) throws SQLException { checkGroupCycles(group); dataManager.addGroup(group); - groupsLock.writeLock().lock(); - try { - groupsById.put(group.getId(), group); - } finally { - groupsLock.writeLock().unlock(); - } + groupsById.put(group.getId(), group); } public void updateGroup(Group group) throws SQLException { checkGroupCycles(group); dataManager.updateGroup(group); - groupsLock.writeLock().lock(); - try { - groupsById.put(group.getId(), group); - } finally { - groupsLock.writeLock().unlock(); - } + groupsById.put(group.getId(), group); } public void removeGroup(long groupId) throws SQLException { dataManager.removeGroup(groupId); - groupsLock.writeLock().lock(); - try { - groupsById.remove(groupId); - } finally { - groupsLock.writeLock().unlock(); - } + groupsById.remove(groupId); } } -- cgit v1.2.3 From 35eea73b2b9e381efd5da60662f0f64f59b91406 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Thu, 21 Jul 2016 17:39:04 +0500 Subject: Act with atomic more carefully --- src/org/traccar/database/DeviceManager.java | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src/org/traccar/database') diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index 916e7fe67..f442dfb19 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -43,10 +43,10 @@ public class DeviceManager implements IdentityManager { private Map devicesById; private Map devicesByUniqueId; - private AtomicLong devicesLastUpdate = new AtomicLong(0); + private AtomicLong devicesLastUpdate = new AtomicLong(); private Map groupsById; - private AtomicLong groupsLastUpdate = new AtomicLong(0); + private AtomicLong groupsLastUpdate = new AtomicLong(); private final Map positions = new ConcurrentHashMap<>(); @@ -68,8 +68,10 @@ public class DeviceManager implements IdentityManager { } private void updateDeviceCache(boolean force) throws SQLException { - boolean needWrite = force || System.currentTimeMillis() - devicesLastUpdate.get() > dataRefreshDelay; - if (needWrite) { + + long lastUpdate = devicesLastUpdate.get(); + if (force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay + && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { GeofenceManager geofenceManager = Context.getGeofenceManager(); Collection databaseDevices = dataManager.getAllDevices(); if (devicesById == null) { @@ -79,10 +81,10 @@ public class DeviceManager implements IdentityManager { devicesByUniqueId = new ConcurrentHashMap<>(databaseDevices.size()); } Set databaseDevicesIds = new HashSet<>(); - Set databaseDevicesUniqIds = new HashSet<>(); + Set databaseDevicesUniqueIds = new HashSet<>(); for (Device device : databaseDevices) { databaseDevicesIds.add(device.getId()); - databaseDevicesUniqIds.add(device.getUniqueId()); + databaseDevicesUniqueIds.add(device.getUniqueId()); if (devicesById.containsKey(device.getId())) { Device cachedDevice = devicesById.get(device.getId()); cachedDevice.setName(device.getName()); @@ -112,13 +114,12 @@ public class DeviceManager implements IdentityManager { } } for (String cachedDeviceUniqId : devicesByUniqueId.keySet()) { - if (!databaseDevicesUniqIds.contains(cachedDeviceUniqId)) { + if (!databaseDevicesUniqueIds.contains(cachedDeviceUniqId)) { devicesByUniqueId.remove(cachedDeviceUniqId); } } databaseDevicesIds.clear(); - databaseDevicesUniqIds.clear(); - devicesLastUpdate.set(System.currentTimeMillis()); + databaseDevicesUniqueIds.clear(); } } @@ -230,9 +231,10 @@ public class DeviceManager implements IdentityManager { } private void updateGroupCache(boolean force) throws SQLException { - boolean needWrite = force || System.currentTimeMillis() - groupsLastUpdate.get() > dataRefreshDelay; - if (needWrite) { + long lastUpdate = groupsLastUpdate.get(); + if (force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay + && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { Collection databaseGroups = dataManager.getAllGroups(); if (groupsById == null) { groupsById = new ConcurrentHashMap<>(databaseGroups.size()); @@ -254,7 +256,6 @@ public class DeviceManager implements IdentityManager { } } databaseGroupsIds.clear(); - groupsLastUpdate.set(System.currentTimeMillis()); } } -- cgit v1.2.3 From e269c81b1b8044d051196e97f0884935c153feb0 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Thu, 21 Jul 2016 17:44:57 +0500 Subject: Added parentheses --- src/org/traccar/database/DeviceManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/org/traccar/database') diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index f442dfb19..4dd7b41cb 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -70,7 +70,7 @@ public class DeviceManager implements IdentityManager { private void updateDeviceCache(boolean force) throws SQLException { long lastUpdate = devicesLastUpdate.get(); - if (force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay + if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { GeofenceManager geofenceManager = Context.getGeofenceManager(); Collection databaseDevices = dataManager.getAllDevices(); @@ -233,7 +233,7 @@ public class DeviceManager implements IdentityManager { private void updateGroupCache(boolean force) throws SQLException { long lastUpdate = groupsLastUpdate.get(); - if (force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay + if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { Collection databaseGroups = dataManager.getAllGroups(); if (groupsById == null) { -- cgit v1.2.3