Browse Source

Merge pull request #3888 from YevhenBondarenko/fix-device-profile-service

fix ConstraintViolationException on findOrCreateDeviceProfile
pull/3893/head
Igor Kulikov 6 years ago
committed by GitHub
parent
commit
bb643df296
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  2. 24
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

16
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -64,8 +64,10 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE;
import static org.thingsboard.server.dao.service.Validator.validateId;
@ -101,6 +103,8 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
@Autowired
private CacheManager cacheManager;
private final Lock findOrCreateLock = new ReentrantLock();
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")
@Override
public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId) {
@ -220,7 +224,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
log.trace("Executing findOrCreateDefaultDeviceProfile");
DeviceProfile deviceProfile = findDeviceProfileByName(tenantId, name);
if (deviceProfile == null) {
deviceProfile = this.doCreateDefaultDeviceProfile(tenantId, name, name.equals("default"));
try {
findOrCreateLock.lock();
deviceProfile = findDeviceProfileByName(tenantId, name);
if (deviceProfile == null) {
deviceProfile = this.doCreateDefaultDeviceProfile(tenantId, name, name.equals("default"));
}
} finally {
findOrCreateLock.unlock();
}
}
return deviceProfile;
}

24
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

@ -15,6 +15,10 @@
*/
package org.thingsboard.server.dao.service;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -34,6 +38,9 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@ -112,6 +119,23 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
Assert.assertNotNull(foundDefaultDeviceProfileInfo.getType());
}
@Test
public void testFindOrCreateDeviceProfile() throws ExecutionException, InterruptedException {
ListeningExecutorService testExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(100));
try {
List<ListenableFuture<DeviceProfile>> futures = new ArrayList<>();
for (int i = 0; i < 50; i ++) {
futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 1")));
futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 2")));
}
List<DeviceProfile> deviceProfiles = Futures.allAsList(futures).get();
deviceProfiles.forEach(Assert::assertNotNull);
} finally {
testExecutor.shutdownNow();
}
}
@Test
public void testSetDefaultDeviceProfile() {
DeviceProfile deviceProfile1 = this.createDeviceProfile(tenantId,"Device Profile 1");

Loading…
Cancel
Save