Skip to content

Commit 2321322

Browse files
committed
SEBSP-210 live screenshot data cache PoC impl finished
1 parent f956a05 commit 2321322

File tree

14 files changed

+388
-148
lines changed

14 files changed

+388
-148
lines changed

src/main/java/ch/ethz/seb/sps/server/ServiceUpdateTask.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import static ch.ethz.seb.sps.server.ServiceConfig.SYSTEM_SCHEDULER;
1212

13+
import ch.ethz.seb.sps.server.servicelayer.LiveProctoringCacheService;
1314
import org.springframework.beans.factory.DisposableBean;
1415
import org.springframework.beans.factory.annotation.Value;
1516
import org.springframework.context.annotation.Lazy;
@@ -22,13 +23,16 @@
2223
public class ServiceUpdateTask implements DisposableBean {
2324

2425
private final ServiceInfo serviceInfo;
26+
private final LiveProctoringCacheService liveProctoringCacheService;
2527
private final long updateInterval;
2628

2729
public ServiceUpdateTask(
28-
final ServiceInfo serviceInfo,
30+
final ServiceInfo serviceInfo,
31+
final LiveProctoringCacheService liveProctoringCacheService,
2932
@Value("${sps.webservice.distributed.update:15000}") final long updateInterval) {
3033

3134
this.serviceInfo = serviceInfo;
35+
this.liveProctoringCacheService = liveProctoringCacheService;
3236
this.updateInterval = updateInterval;
3337
}
3438

@@ -53,6 +57,8 @@ private void init() {
5357
scheduler = SYSTEM_SCHEDULER)
5458
private void sessionUpdateTask() {
5559
this.serviceInfo.updateMaster();
60+
61+
liveProctoringCacheService.cleanup(this.serviceInfo.isMaster());
5662
}
5763

5864
@Override

src/main/java/ch/ethz/seb/sps/server/datalayer/dao/ScreenshotDataDAO.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ public interface ScreenshotDataDAO extends EntityDAO<ScreenshotData, ScreenshotD
3434

3535
Result<Long> getIdAt(String sessionUUID, Long at);
3636

37-
Result<Long> getLatestImageId(String sessionUUID);
37+
//Result<Long> getLatestImageId(String sessionUUID);
3838

3939
Result<Collection<Long>> getScreenshotTimestamps(String sessionUUID, Long timestamp, PageSortOrder sortOrder);
4040

4141
Result<ScreenshotDataRecord> getLatest(String sessionUUID);
4242

43-
Result<Map<String, ScreenshotDataRecord>> allLatestIn(List<String> sessionUUIDs);
43+
Result<Map<String, ScreenshotDataRecord>> allOfMappedToSession(List<Long> pks);
44+
//Result<Map<String, ScreenshotDataRecord>> allLatestIn(List<String> sessionUUIDs);
4445

4546
Result<Long> save(
4647
String sessionId,
@@ -62,4 +63,5 @@ Result<Long> save(
6263

6364
Result<List<Long>> getTimestampListForApplicationSearch(String sessionUuid, String metadataApplication, String metadataWindowTitle);
6465

66+
Result<ScreenshotDataRecord> recordByPK(Long latestSSDataId);
6567
}

src/main/java/ch/ethz/seb/sps/server/datalayer/dao/ScreenshotDataLiveCacheDAO.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public interface ScreenshotDataLiveCacheDAO {
1818

1919
Result<ScreenshotDataLiveCacheRecord> createCacheEntry(String sessionUUID);
2020

21+
Result<ScreenshotDataLiveCacheRecord> createCacheEntry(String sessionUUID, Long value);
22+
2123
Result<String> deleteCacheEntry(String sessionUUID);
2224

2325
Result<List<String>> deleteAll(List<String> sessionUUIDs);

src/main/java/ch/ethz/seb/sps/server/datalayer/dao/impl/ScreenshotDataDAOBatis.java

Lines changed: 82 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ public Result<Collection<ScreenshotData>> allOfSession(final String sessionUUID)
126126
@Override
127127
@Transactional(readOnly = true)
128128
public Result<ScreenshotDataRecord> getAt(final String sessionUUID, final Long at) {
129+
130+
System.out.print("******************** getAt called for session: " + sessionUUID + " with at: " + at);
131+
129132
// TODO: this seems to produce performance issues when table is huge. Try to optimize query by reducing the time frame here
130133
return Result.tryCatch(() -> {
131134
ScreenshotDataRecord record = SelectDSL
@@ -178,6 +181,8 @@ record = SelectDSL
178181
public Result<Long> getIdAt(final String sessionUUID, final Long at) {
179182
return Result.tryCatch(() -> {
180183

184+
System.out.println("******************** getIdAt called for session: " + sessionUUID + " with at: " + at);
185+
181186
List<Long> result = SelectDSL
182187
.selectWithMapper(this.screenshotDataRecordMapper::selectIds, id, timestamp)
183188
.from(screenshotDataRecord)
@@ -211,28 +216,33 @@ public Result<Long> getIdAt(final String sessionUUID, final Long at) {
211216
});
212217
}
213218

214-
@Override
215-
@Transactional(readOnly = true)
216-
public Result<Long> getLatestImageId(final String sessionUUID) {
217-
return Result.tryCatch(() -> {
218-
219-
final List<Long> execute = SelectDSL
220-
.selectDistinctWithMapper(this.screenshotDataRecordMapper::selectIds, id, timestamp)
221-
.from(screenshotDataRecord)
222-
.where(ScreenshotDataRecordDynamicSqlSupport.sessionUuid, SqlBuilder.isEqualTo(sessionUUID))
223-
.orderBy(timestamp.descending())
224-
.limit(1)
225-
.build()
226-
.execute();
227-
228-
return execute.get(0);
229-
});
230-
}
219+
// @Override
220+
// @Transactional(readOnly = true)
221+
// public Result<Long> getLatestImageId(final String sessionUUID) {
222+
// return Result.tryCatch(() -> {
223+
//
224+
// System.out.println("******************** getLatestImageId called for session: " + sessionUUID );
225+
//
226+
// final List<Long> execute = SelectDSL
227+
// .selectDistinctWithMapper(this.screenshotDataRecordMapper::selectIds, id, timestamp)
228+
// .from(screenshotDataRecord)
229+
// .where(ScreenshotDataRecordDynamicSqlSupport.sessionUuid, SqlBuilder.isEqualTo(sessionUUID))
230+
// .orderBy(timestamp.descending())
231+
// .limit(1)
232+
// .build()
233+
// .execute();
234+
//
235+
// return execute.get(0);
236+
// });
237+
// }
231238

232239
@Override
233240
@Transactional(readOnly = true)
234241
public Result<ScreenshotDataRecord> getLatest(final String sessionUUID) {
235242
return Result.tryCatch(() -> {
243+
244+
System.out.println("******************** getLatest called for session: " + sessionUUID );
245+
236246
final ScreenshotDataRecord latestScreenshotDataRec = getLatestScreenshotDataRec(sessionUUID);
237247
if (latestScreenshotDataRec == null) {
238248
throw new NoResourceFoundException(EntityType.SCREENSHOT_DATA, sessionUUID);
@@ -242,42 +252,60 @@ public Result<ScreenshotDataRecord> getLatest(final String sessionUUID) {
242252
}
243253

244254
@Override
245-
@Transactional(readOnly = true)
246-
public Result<Map<String, ScreenshotDataRecord>> allLatestIn(final List<String> sessionUUIDs) {
255+
public Result<Map<String, ScreenshotDataRecord>> allOfMappedToSession(final List<Long> pks) {
247256
return Result.tryCatch(() -> {
248-
if (sessionUUIDs == null || sessionUUIDs.isEmpty()) {
257+
258+
if (pks == null || pks.isEmpty()) {
249259
return Collections.emptyMap();
250260
}
251261

252-
// NOTE: This was not working as expected since limit does not work with group (groupBy)
253-
// return SelectDSL
254-
// .selectWithMapper(this.screenshotDataRecordMapper::selectMany,
255-
// id,
256-
// sessionUuid,
257-
// timestamp,
258-
// imageFormat,
259-
// metaData)
260-
// .from(screenshotDataRecord)
261-
// .where(ScreenshotDataRecordDynamicSqlSupport.sessionUuid, SqlBuilder.isIn(sessionUUIDs))
262-
// .groupBy(ScreenshotDataRecordDynamicSqlSupport.sessionUuid)
263-
// .orderBy(timestamp.descending())
264-
// .limit(1)
265-
// .build()
266-
// .execute()
267-
// .stream()
268-
// .collect(Collectors.toMap(r -> r.getSessionUuid(), Function.identity()));
269-
270-
// NOTE: For now we use a less efficient version that uses getLatest(final String sessionUUID) for
271-
// all requested sessions but in the future we should solve this problem on DB layer
272-
return sessionUUIDs.stream()
273-
.map(this::getLatestScreenshotDataRec)
274-
.filter(Objects::nonNull)
275-
.collect(Collectors.toMap(
276-
ScreenshotDataRecord::getSessionUuid,
277-
Function.identity()));
262+
return screenshotDataRecordMapper
263+
.selectByExample()
264+
.where(id, isIn(pks))
265+
.build()
266+
.execute()
267+
.stream()
268+
.collect(Collectors.toMap(r -> r.getSessionUuid(), Function.identity()));
278269
});
279270
}
280271

272+
// @Override
273+
// @Transactional(readOnly = true)
274+
// public Result<Map<String, ScreenshotDataRecord>> allLatestIn(final List<String> sessionUUIDs) {
275+
// return Result.tryCatch(() -> {
276+
// if (sessionUUIDs == null || sessionUUIDs.isEmpty()) {
277+
// return Collections.emptyMap();
278+
// }
279+
//
280+
// // NOTE: This was not working as expected since limit does not work with group (groupBy)
281+
//// return SelectDSL
282+
//// .selectWithMapper(this.screenshotDataRecordMapper::selectMany,
283+
//// id,
284+
//// sessionUuid,
285+
//// timestamp,
286+
//// imageFormat,
287+
//// metaData)
288+
//// .from(screenshotDataRecord)
289+
//// .where(ScreenshotDataRecordDynamicSqlSupport.sessionUuid, SqlBuilder.isIn(sessionUUIDs))
290+
//// .groupBy(ScreenshotDataRecordDynamicSqlSupport.sessionUuid)
291+
//// .orderBy(timestamp.descending())
292+
//// .limit(1)
293+
//// .build()
294+
//// .execute()
295+
//// .stream()
296+
//// .collect(Collectors.toMap(r -> r.getSessionUuid(), Function.identity()));
297+
//
298+
// // NOTE: For now we use a less efficient version that uses getLatest(final String sessionUUID) for
299+
// // all requested sessions but in the future we should solve this problem on DB layer
300+
// return sessionUUIDs.stream()
301+
// .map(this::getLatestScreenshotDataRec)
302+
// .filter(Objects::nonNull)
303+
// .collect(Collectors.toMap(
304+
// ScreenshotDataRecord::getSessionUuid,
305+
// Function.identity()));
306+
// });
307+
// }
308+
281309
@Override
282310
@Transactional(readOnly = true)
283311
public Result<Collection<ScreenshotData>> allMatching(
@@ -709,7 +737,15 @@ public Result<List<Long>> getTimestampListForApplicationSearch(
709737
});
710738
}
711739

740+
@Override
741+
public Result<ScreenshotDataRecord> recordByPK(Long pk) {
742+
return Result.tryCatch(() -> this.screenshotDataRecordMapper.selectByPrimaryKey(pk));
743+
}
744+
712745
private ScreenshotDataRecord getLatestScreenshotDataRec(final String sessionUUID) {
746+
747+
System.out.println("******************** getLatestScreenshotDataRec called for session: " + sessionUUID );
748+
713749
return SelectDSL
714750
.selectWithMapper(this.screenshotDataRecordMapper::selectOne,
715751
id,

src/main/java/ch/ethz/seb/sps/server/datalayer/dao/impl/ScreenshotDataLiveCacheDAOBatis.java

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,92 @@
1111
import java.util.Collection;
1212
import java.util.List;
1313

14+
import ch.ethz.seb.sps.server.datalayer.batis.mapper.ScreenshotDataLiveCacheRecordDynamicSqlSupport;
15+
import ch.ethz.seb.sps.server.datalayer.batis.mapper.ScreenshotDataLiveCacheRecordMapper;
1416
import ch.ethz.seb.sps.server.datalayer.batis.model.ScreenshotDataLiveCacheRecord;
1517
import ch.ethz.seb.sps.server.datalayer.dao.ScreenshotDataLiveCacheDAO;
1618
import ch.ethz.seb.sps.utils.Result;
19+
import org.mybatis.dynamic.sql.SqlBuilder;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
1722
import org.springframework.stereotype.Service;
23+
import org.springframework.transaction.annotation.Transactional;
1824

1925
@Service
2026
public class ScreenshotDataLiveCacheDAOBatis implements ScreenshotDataLiveCacheDAO {
21-
27+
28+
private static final Logger log = LoggerFactory.getLogger(ScreenshotDataLiveCacheDAOBatis.class);
29+
30+
private final ScreenshotDataLiveCacheRecordMapper screenshotDataLiveCacheRecordMapper;
31+
32+
public ScreenshotDataLiveCacheDAOBatis(ScreenshotDataLiveCacheRecordMapper screenshotDataLiveCacheRecordMapper) {
33+
this.screenshotDataLiveCacheRecordMapper = screenshotDataLiveCacheRecordMapper;
34+
}
35+
2236
@Override
37+
@Transactional
2338
public Result<ScreenshotDataLiveCacheRecord> createCacheEntry(String sessionUUID) {
24-
return null;
25-
// return Result.tryCatch(() -> {
26-
// new ScreenshotDataLiveCacheRecord( null, sessionUUID, -1L );
27-
// });
39+
return Result
40+
.tryCatch(() -> screenshotDataLiveCacheRecordMapper.selectByPrimaryKey(createSlot(sessionUUID, -1L)))
41+
.onError(TransactionHandler::rollback);
42+
}
43+
44+
@Override
45+
@Transactional
46+
public Result<ScreenshotDataLiveCacheRecord> createCacheEntry(String sessionUUID, Long value) {
47+
return Result
48+
.tryCatch(() -> screenshotDataLiveCacheRecordMapper.selectByPrimaryKey(createSlot(sessionUUID, value)))
49+
.onError(TransactionHandler::rollback);
2850
}
2951

3052
@Override
53+
@Transactional
3154
public Result<String> deleteCacheEntry(String sessionUUID) {
32-
return null;
55+
return Result.tryCatch(() -> {
56+
screenshotDataLiveCacheRecordMapper
57+
.deleteByExample()
58+
.where(
59+
ScreenshotDataLiveCacheRecordDynamicSqlSupport.sessionUuid,
60+
SqlBuilder.isEqualTo(sessionUUID))
61+
.build()
62+
.execute();
63+
64+
return sessionUUID;
65+
}).
66+
onError(TransactionHandler::rollback);
3367
}
3468

3569
@Override
70+
@Transactional
3671
public Result<List<String>> deleteAll(List<String> sessionUUIDs) {
37-
return null;
72+
return Result.tryCatch(() -> {
73+
74+
screenshotDataLiveCacheRecordMapper
75+
.deleteByExample()
76+
.where(
77+
ScreenshotDataLiveCacheRecordDynamicSqlSupport.sessionUuid,
78+
SqlBuilder.isIn(sessionUUIDs))
79+
.build()
80+
.execute();
81+
82+
return sessionUUIDs;
83+
}).
84+
onError(TransactionHandler::rollback);
3885
}
3986

4087
@Override
88+
@Transactional(readOnly = true)
4189
public Result<Collection<ScreenshotDataLiveCacheRecord>> getAll() {
42-
return null;
90+
return Result.tryCatch(() -> screenshotDataLiveCacheRecordMapper.selectByExample().build().execute());
91+
}
92+
93+
private synchronized Long createSlot(String sessionUUID, Long value) {
94+
final ScreenshotDataLiveCacheRecord rec = new ScreenshotDataLiveCacheRecord(
95+
null,
96+
sessionUUID,
97+
value );
98+
99+
screenshotDataLiveCacheRecordMapper.insert(rec);
100+
return rec.getId();
43101
}
44102
}

src/main/java/ch/ethz/seb/sps/server/servicelayer/LiveProctoringCacheService.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,24 @@ public interface LiveProctoringCacheService {
2424
*
2525
* @param sessionUUID The live session UUID
2626
* @return PK id of the last screenshot_data row if available or -1 if there is no screenshot yet or null if there is no slot for the given sessionUUID*/
27-
Long getLatestSSDataId(String sessionUUID);
28-
29-
/** Creates a new cache slot for given session. Usually called when session is created
30-
*
31-
* @param sessionUUID Session UUID to create a live cache slot for
32-
* @return Result refer to given sessionUUID or to an error when happened */
33-
Result<String> createCacheSlot(String sessionUUID);
34-
35-
/** Deletes a cache slot for a given session. Usually called when session is closed
36-
*
37-
* @param sessionUUID Session UUID to create a live cache slot for
38-
* @return Result refer to given sessionUUID or to an error when happened */
39-
Result<String> deleteCacheSlot(String sessionUUID);
27+
Long getLatestSSDataId(String sessionUUID, boolean createSlot);
28+
29+
// /** Creates a new cache slot for given session. Usually called when session is created
30+
// *
31+
// * @param sessionUUID Session UUID to create a live cache slot for
32+
// * @return Result refer to given sessionUUID or to an error when happened */
33+
// Result<String> createCacheSlot(String sessionUUID);
34+
//
35+
// /** Deletes a cache slot for a given session. Usually called when session is closed
36+
// *
37+
// * @param sessionUUID Session UUID to create a live cache slot for
38+
// * @return Result refer to given sessionUUID or to an error when happened */
39+
// Result<String> deleteCacheSlot(String sessionUUID);
4040

4141
/** Called by the batch store services to update latest cache entries on storage
4242
* @param batch The batch with the latest screenshot_data ids */
4343
void updateCacheStore(Collection<ScreenshotQueueData> batch);
4444

4545
/** Goes through all cache slots and deletes the one that has a closed session */
46-
void cleanup();
46+
void cleanup(boolean isMaster);
4747
}

0 commit comments

Comments
 (0)