Skip to content

Commit cf0b231

Browse files
Programming Challenge redislabs-training#3
1 parent c82b370 commit cf0b231

File tree

2 files changed

+88
-77
lines changed

2 files changed

+88
-77
lines changed

src/main/java/com/redislabs/university/RU102J/api/SiteStats.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class SiteStats {
1212
private Double minWhGenerated;
1313
private Double maxCapacity;
1414

15+
1516
/* These field names will be used by multiple classes, so we define
1617
them here to abide by DRY (don't repeat yourself). */
1718
public final static String reportingTimeField = "lastReportingTime";

src/main/java/com/redislabs/university/RU102J/dao/SiteStatsDaoRedisImpl.java

Lines changed: 87 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,88 +3,98 @@
33
import com.redislabs.university.RU102J.api.MeterReading;
44
import com.redislabs.university.RU102J.api.SiteStats;
55
import com.redislabs.university.RU102J.script.CompareAndUpdateScript;
6-
import redis.clients.jedis.Jedis;
7-
import redis.clients.jedis.JedisPool;
8-
import redis.clients.jedis.Transaction;
96

107
import java.time.ZoneOffset;
118
import java.time.ZonedDateTime;
129
import java.util.Map;
1310

11+
import redis.clients.jedis.Jedis;
12+
import redis.clients.jedis.JedisPool;
13+
import redis.clients.jedis.Transaction;
14+
1415
public class SiteStatsDaoRedisImpl implements SiteStatsDao {
1516

16-
private final int weekSeconds = 60 * 60 * 24 * 7;
17-
private final JedisPool jedisPool;
18-
private final CompareAndUpdateScript compareAndUpdateScript;
19-
20-
public SiteStatsDaoRedisImpl(JedisPool jedisPool) {
21-
this.jedisPool = jedisPool;
22-
this.compareAndUpdateScript = new CompareAndUpdateScript(jedisPool);
23-
}
24-
25-
// Returns the site stats for the current day
26-
@Override
27-
public SiteStats findById(long siteId) {
28-
return findById(siteId, ZonedDateTime.now());
29-
}
30-
31-
@Override
32-
public SiteStats findById(long siteId, ZonedDateTime day) {
33-
try (Jedis jedis = jedisPool.getResource()) {
34-
String key = RedisSchema.getSiteStatsKey(siteId, day);
35-
Map<String, String> fields = jedis.hgetAll(key);
36-
if (fields == null || fields.isEmpty()) {
37-
return null;
38-
}
39-
return new SiteStats(fields);
40-
}
41-
}
42-
43-
@Override
44-
public void update(MeterReading reading) {
45-
try (Jedis jedis = jedisPool.getResource()) {
46-
Long siteId = reading.getSiteId();
47-
ZonedDateTime day = reading.getDateTime();
48-
String key = RedisSchema.getSiteStatsKey(siteId, day);
49-
50-
updateBasic(jedis, key, reading);
51-
}
52-
}
53-
54-
// A naive implementation of update. This implementation has
55-
// potential race conditions and makes several round trips to Redis.
56-
private void updateBasic(Jedis jedis, String key, MeterReading reading) {
57-
String reportingTime = ZonedDateTime.now(ZoneOffset.UTC).toString();
58-
jedis.hset(key, SiteStats.reportingTimeField, reportingTime);
59-
jedis.hincrBy(key, SiteStats.countField, 1);
60-
jedis.expire(key, weekSeconds);
61-
62-
String maxWh = jedis.hget(key, SiteStats.maxWhField);
63-
if (maxWh == null || reading.getWhGenerated() > Double.valueOf(maxWh)) {
64-
jedis.hset(key, SiteStats.maxWhField,
65-
String.valueOf(reading.getWhGenerated()));
66-
}
67-
68-
String minWh = jedis.hget(key, SiteStats.minWhField);
69-
if (minWh == null || reading.getWhGenerated() < Double.valueOf(minWh)) {
70-
jedis.hset(key, SiteStats.minWhField,
71-
String.valueOf(reading.getWhGenerated()));
72-
}
73-
74-
String maxCapacity = jedis.hget(key, SiteStats.maxCapacityField);
75-
if (maxCapacity == null || getCurrentCapacity(reading) > Double.valueOf(maxCapacity)) {
76-
jedis.hset(key, SiteStats.maxCapacityField,
77-
String.valueOf(getCurrentCapacity(reading)));
78-
}
79-
}
80-
81-
// Challenge #3
82-
private void updateOptimized(Jedis jedis, String key, MeterReading reading) {
83-
// START Challenge #3
84-
// END Challenge #3
85-
}
86-
87-
private Double getCurrentCapacity(MeterReading reading) {
88-
return reading.getWhGenerated() - reading.getWhUsed();
89-
}
17+
private final int weekSeconds = 60 * 60 * 24 * 7;
18+
private final JedisPool jedisPool;
19+
private final CompareAndUpdateScript compareAndUpdateScript;
20+
21+
public SiteStatsDaoRedisImpl( JedisPool jedisPool ) {
22+
this.jedisPool = jedisPool;
23+
this.compareAndUpdateScript = new CompareAndUpdateScript( jedisPool );
24+
}
25+
26+
// Returns the site stats for the current day
27+
@Override
28+
public SiteStats findById( long siteId ) {
29+
return findById( siteId, ZonedDateTime.now() );
30+
}
31+
32+
@Override
33+
public SiteStats findById( long siteId, ZonedDateTime day ) {
34+
try ( Jedis jedis = jedisPool.getResource() ) {
35+
String key = RedisSchema.getSiteStatsKey( siteId, day );
36+
Map<String, String> fields = jedis.hgetAll( key );
37+
if ( fields == null || fields.isEmpty() ) {
38+
return null;
39+
}
40+
return new SiteStats( fields );
41+
}
42+
}
43+
44+
@Override
45+
public void update( MeterReading reading ) {
46+
try ( Jedis jedis = jedisPool.getResource() ) {
47+
Long siteId = reading.getSiteId();
48+
ZonedDateTime day = reading.getDateTime();
49+
String key = RedisSchema.getSiteStatsKey( siteId, day );
50+
51+
updateOptimized( jedis, key, reading );
52+
}
53+
}
54+
55+
// A naive implementation of update. This implementation has
56+
// potential race conditions and makes several round trips to Redis.
57+
private void updateBasic( Jedis jedis, String key, MeterReading reading ) {
58+
String reportingTime = ZonedDateTime.now( ZoneOffset.UTC ).toString();
59+
jedis.hset( key, SiteStats.reportingTimeField, reportingTime );
60+
jedis.hincrBy( key, SiteStats.countField, 1 );
61+
jedis.expire( key, weekSeconds );
62+
63+
String maxWh = jedis.hget( key, SiteStats.maxWhField );
64+
if ( maxWh == null || reading.getWhGenerated() > Double.valueOf( maxWh ) ) {
65+
jedis.hset( key, SiteStats.maxWhField, String.valueOf( reading.getWhGenerated() ) );
66+
}
67+
68+
String minWh = jedis.hget( key, SiteStats.minWhField );
69+
if ( minWh == null || reading.getWhGenerated() < Double.valueOf( minWh ) ) {
70+
jedis.hset( key, SiteStats.minWhField, String.valueOf( reading.getWhGenerated() ) );
71+
}
72+
73+
String maxCapacity = jedis.hget( key, SiteStats.maxCapacityField );
74+
if ( maxCapacity == null || getCurrentCapacity( reading ) > Double.valueOf( maxCapacity ) ) {
75+
jedis.hset( key, SiteStats.maxCapacityField, String.valueOf( getCurrentCapacity( reading ) ) );
76+
}
77+
}
78+
79+
// Challenge #3
80+
private void updateOptimized( Jedis jedis, String key, MeterReading reading ) {
81+
String reportingTime = ZonedDateTime.now( ZoneOffset.UTC ).toString();
82+
83+
jedis.hset( key, SiteStats.reportingTimeField, reportingTime );
84+
jedis.hincrBy( key, SiteStats.countField, 1 );
85+
jedis.expire( key, weekSeconds );
86+
87+
Transaction transaction = jedis.multi();
88+
89+
compareAndUpdateScript.updateIfGreater( transaction, key, SiteStats.maxWhField, reading.getWhGenerated() );
90+
compareAndUpdateScript.updateIfLess( transaction, key, SiteStats.minWhField, reading.getWhGenerated() );
91+
compareAndUpdateScript.updateIfGreater( transaction, key, SiteStats.maxCapacityField, getCurrentCapacity( reading ) );
92+
93+
transaction.exec();
94+
transaction.close();
95+
}
96+
97+
private Double getCurrentCapacity( MeterReading reading ) {
98+
return reading.getWhGenerated() - reading.getWhUsed();
99+
}
90100
}

0 commit comments

Comments
 (0)