Skip to content

Commit 1a741d0

Browse files
committed
support commit/rollback in DataStorage
1 parent 58c145c commit 1a741d0

File tree

7 files changed

+162
-87
lines changed

7 files changed

+162
-87
lines changed

agent/storage/src/main/java/me/hsgamer/topper/agent/storage/StorageAgent.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,24 @@ private void save(boolean urgent) {
6565
})
6666
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
6767

68+
69+
Optional<DataStorage.Modifier<K, V>> optionalModifier = storage.modify();
70+
if (!optionalModifier.isPresent()) {
71+
saving.set(false);
72+
return;
73+
}
74+
75+
DataStorage.Modifier<K, V> modifier = optionalModifier.get();
6876
try {
69-
storage.save(finalMap);
77+
modifier.save(finalMap);
7078
if (!removeKeys.isEmpty()) {
71-
storage.remove(removeKeys);
79+
modifier.remove(removeKeys);
7280
}
81+
modifier.commit();
7382
savingMap.set(null);
7483
} catch (Throwable t) {
7584
logger.log(Level.SEVERE, "Failed to save entries for " + holder.getName(), t);
85+
modifier.rollback();
7686
} finally {
7787
saving.set(false);
7888
}

spigot/storage-simple/src/main/java/me/hsgamer/topper/spigot/storage/simple/supplier/ConfigStorageSupplier.java

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
import me.hsgamer.topper.storage.simple.supplier.DataStorageSupplier;
88

99
import java.io.File;
10-
import java.util.Collection;
11-
import java.util.HashMap;
12-
import java.util.Map;
13-
import java.util.Optional;
10+
import java.util.*;
1411
import java.util.function.Function;
1512
import java.util.function.UnaryOperator;
1613

@@ -50,21 +47,42 @@ public Map<K, V> load() {
5047
return map;
5148
}
5249

53-
@Override
54-
public void save(Map<K, V> map) {
55-
map.forEach((key, value) -> config.set(converter.toRawValue(value), converter.toRawKey(key)));
56-
config.save();
57-
}
58-
5950
@Override
6051
public Optional<V> load(K key) {
6152
return Optional.ofNullable(config.get(converter.toRawKey(key))).map(String::valueOf).map(converter::toValue);
6253
}
6354

6455
@Override
65-
public void remove(Collection<K> keys) {
66-
keys.forEach(key -> config.remove(converter.toRawKey(key)));
67-
config.save();
56+
public Optional<Modifier<K, V>> modify() {
57+
return Optional.of(new Modifier<K, V>() {
58+
private final Map<K, V> map = new HashMap<>();
59+
private final Set<K> removeSet = new HashSet<>();
60+
61+
@Override
62+
public void save(Map<K, V> map) {
63+
this.map.putAll(map);
64+
this.removeSet.removeIf(this.map::containsKey);
65+
}
66+
67+
@Override
68+
public void remove(Collection<K> keys) {
69+
this.removeSet.addAll(keys);
70+
this.removeSet.forEach(map::remove);
71+
}
72+
73+
@Override
74+
public void commit() {
75+
map.forEach((k, v) -> config.set(converter.toRawKey(k), converter.toRawValue(v)));
76+
removeSet.forEach(key -> config.remove(converter.toRawKey(key)));
77+
config.save();
78+
}
79+
80+
@Override
81+
public void rollback() {
82+
map.clear();
83+
removeSet.clear();
84+
}
85+
});
6886
}
6987

7088
@Override

storage/core/src/main/java/me/hsgamer/topper/storage/core/DataStorage.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@
77
public interface DataStorage<K, V> {
88
Map<K, V> load();
99

10-
void save(Map<K, V> map);
11-
1210
Optional<V> load(K key);
1311

14-
void remove(Collection<K> keys);
12+
Optional<Modifier<K, V>> modify();
1513

1614
default void onRegister() {
1715
// EMPTY
@@ -20,4 +18,14 @@ default void onRegister() {
2018
default void onUnregister() {
2119
// EMPTY
2220
}
21+
22+
interface Modifier<K, V> {
23+
void save(Map<K, V> map) throws Exception;
24+
25+
void remove(Collection<K> keys) throws Exception;
26+
27+
void commit();
28+
29+
void rollback();
30+
}
2331
}

storage/simple/src/main/java/me/hsgamer/topper/storage/simple/supplier/FlatStorageSupplier.java

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,42 @@ public Map<K, V> load() {
6666
return map;
6767
}
6868

69-
@Override
70-
public void save(Map<K, V> map) {
71-
map.forEach((k, v) -> properties.put(converter.toRawKey(k), converter.toRawValue(v)));
72-
saveRunnable.run();
73-
}
74-
7569
@Override
7670
public Optional<V> load(K key) {
7771
return Optional.ofNullable(properties.getProperty(converter.toRawKey(key))).map(converter::toValue);
7872
}
7973

8074
@Override
81-
public void remove(Collection<K> keys) {
82-
keys.forEach(key -> properties.remove(converter.toRawKey(key)));
83-
saveRunnable.run();
75+
public Optional<Modifier<K, V>> modify() {
76+
return Optional.of(new Modifier<K, V>() {
77+
private final Map<K, V> map = new HashMap<>();
78+
private final Set<K> removeSet = new HashSet<>();
79+
80+
@Override
81+
public void save(Map<K, V> map) {
82+
this.map.putAll(map);
83+
this.removeSet.removeIf(this.map::containsKey);
84+
}
85+
86+
@Override
87+
public void remove(Collection<K> keys) {
88+
this.removeSet.addAll(keys);
89+
this.removeSet.forEach(map::remove);
90+
}
91+
92+
@Override
93+
public void commit() {
94+
map.forEach((k, v) -> properties.put(converter.toRawKey(k), converter.toRawValue(v)));
95+
removeSet.forEach(key -> properties.remove(converter.toRawKey(key)));
96+
saveRunnable.run();
97+
}
98+
99+
@Override
100+
public void rollback() {
101+
map.clear();
102+
removeSet.clear();
103+
}
104+
});
84105
}
85106

86107
@Override

storage/simple/src/main/java/me/hsgamer/topper/storage/simple/supplier/MySqlStorageSupplier.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public MySqlStorageSupplier(Consumer<Setting> databaseSettingConsumer) {
2222

2323
@Override
2424
protected Connection getConnection() throws SQLException {
25-
return client.getConnection();
25+
Connection connection = client.getConnection();
26+
connection.setAutoCommit(false);
27+
return connection;
2628
}
2729

2830
@Override

storage/simple/src/main/java/me/hsgamer/topper/storage/simple/supplier/SqlStorageSupplier.java

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -50,39 +50,6 @@ public Map<K, V> load() {
5050
}
5151
}
5252

53-
@Override
54-
public void save(Map<K, V> map) {
55-
Connection connection = null;
56-
try {
57-
connection = getConnection();
58-
String[] keyColumns = converter.getKeyColumns();
59-
String[] valueColumns = converter.getValueColumns();
60-
61-
List<String> statement = toSaveStatement(name, keyColumns, valueColumns);
62-
List<List<Object[]>> values = new ArrayList<>();
63-
64-
map.forEach((key, value) -> {
65-
Object[] keyValues = converter.toKeyQueryValues(key);
66-
Object[] valueValues = converter.toValueQueryValues(value);
67-
values.add(toSaveValues(keyValues, valueValues));
68-
});
69-
70-
for (int i = 0; i < statement.size(); i++) {
71-
BatchBuilder batchBuilder = BatchBuilder.create(connection, statement.get(i));
72-
for (List<Object[]> value : values) {
73-
batchBuilder.addValues(value.get(i));
74-
}
75-
batchBuilder.execute();
76-
}
77-
} catch (SQLException e) {
78-
logger.log(LogLevel.ERROR, "Failed to save top holder", e);
79-
} finally {
80-
if (connection != null) {
81-
flushConnection(connection);
82-
}
83-
}
84-
}
85-
8653
@Override
8754
public Optional<V> load(K key) {
8855
Connection connection = null;
@@ -120,36 +87,83 @@ public Optional<V> load(K key) {
12087
}
12188

12289
@Override
123-
public void remove(Collection<K> keys) {
124-
Connection connection = null;
90+
public Optional<Modifier<K, V>> modify() {
12591
try {
126-
connection = getConnection();
127-
String[] keyColumns = converter.getKeyColumns();
92+
Connection connection = getConnection();
93+
Modifier<K, V> modifier = new Modifier<K, V>() {
94+
@Override
95+
public void save(Map<K, V> map) throws SQLException {
96+
String[] keyColumns = converter.getKeyColumns();
97+
String[] valueColumns = converter.getValueColumns();
98+
99+
List<String> statement = toSaveStatement(name, keyColumns, valueColumns);
100+
List<List<Object[]>> values = new ArrayList<>();
101+
102+
map.forEach((key, value) -> {
103+
Object[] keyValues = converter.toKeyQueryValues(key);
104+
Object[] valueValues = converter.toValueQueryValues(value);
105+
values.add(toSaveValues(keyValues, valueValues));
106+
});
107+
108+
for (int i = 0; i < statement.size(); i++) {
109+
BatchBuilder batchBuilder = BatchBuilder.create(connection, statement.get(i));
110+
for (List<Object[]> value : values) {
111+
batchBuilder.addValues(value.get(i));
112+
}
113+
batchBuilder.execute();
114+
}
115+
}
128116

129-
StringBuilder statement = new StringBuilder("DELETE FROM `")
130-
.append(name)
131-
.append("` WHERE ");
132-
for (int i = 0; i < keyColumns.length; i++) {
133-
statement.append("`")
134-
.append(keyColumns[i])
135-
.append("` = ?");
136-
if (i != keyColumns.length - 1) {
137-
statement.append(" AND ");
117+
@Override
118+
public void remove(Collection<K> keys) throws SQLException {
119+
String[] keyColumns = converter.getKeyColumns();
120+
121+
StringBuilder statement = new StringBuilder("DELETE FROM `")
122+
.append(name)
123+
.append("` WHERE ");
124+
for (int i = 0; i < keyColumns.length; i++) {
125+
statement.append("`")
126+
.append(keyColumns[i])
127+
.append("` = ?");
128+
if (i != keyColumns.length - 1) {
129+
statement.append(" AND ");
130+
}
131+
}
132+
133+
BatchBuilder batchBuilder = BatchBuilder.create(connection, statement.toString());
134+
keys.forEach(key -> {
135+
Object[] keyValues = converter.toKeyQueryValues(key);
136+
batchBuilder.addValues(keyValues);
137+
});
138+
batchBuilder.execute();
139+
}
140+
141+
@Override
142+
public void commit() {
143+
try {
144+
connection.commit();
145+
} catch (SQLException e) {
146+
logger.log(LogLevel.ERROR, "Failed to commit", e);
147+
} finally {
148+
flushConnection(connection);
149+
}
138150
}
139-
}
140151

141-
BatchBuilder batchBuilder = BatchBuilder.create(connection, statement.toString());
142-
keys.forEach(key -> {
143-
Object[] keyValues = converter.toKeyQueryValues(key);
144-
batchBuilder.addValues(keyValues);
145-
});
146-
batchBuilder.execute();
152+
@Override
153+
public void rollback() {
154+
try {
155+
connection.rollback();
156+
} catch (SQLException e) {
157+
logger.log(LogLevel.ERROR, "Failed to rollback", e);
158+
} finally {
159+
flushConnection(connection);
160+
}
161+
}
162+
};
163+
return Optional.of(modifier);
147164
} catch (SQLException e) {
148-
logger.log(LogLevel.ERROR, "Failed to remove top holder", e);
149-
} finally {
150-
if (connection != null) {
151-
flushConnection(connection);
152-
}
165+
logger.log(LogLevel.ERROR, "Failed to get connection", e);
166+
return Optional.empty();
153167
}
154168
}
155169

storage/simple/src/main/java/me/hsgamer/topper/storage/simple/supplier/SqliteStorageSupplier.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ protected Connection getConnection() {
2727
return connectionReference.updateAndGet(connection -> {
2828
try {
2929
if (connection == null || connection.isClosed()) {
30-
return client.getConnection();
30+
Connection clientConnection = client.getConnection();
31+
clientConnection.setAutoCommit(false);
32+
return clientConnection;
3133
} else {
3234
return connection;
3335
}

0 commit comments

Comments
 (0)