SiNBLOG

140文字に入らないことを、極稀に書くBlog

Slim3 シャーディングカウンタを改良した!

Slim3 シャーディングカウンタ作ってみた。 - SinDiary

先日作成したシャーディングカウンタですが、あおうさ殿にご指南をいただきました!

修正したのはServiceでQueryを使っていたところです。
Queryではなく、Getを用いて取得するようにしました。
それに伴いKeyの生成方法も変更しています。

Google Code Archive - Long-term storage for Google Code Project Hosting.


@Model(schemaVersion = 1)
public class CounterShard implements Serializable {

private static final long serialVersionUID = 1L;

private static final int startKeyNumber = 1;

....

public static Key createKey(CounterShardType name) {
Random random = new Random();
int number = random.nextInt(name.getNumShards()) + startKeyNumber;
return createKey(name, number);
}

public static Key createKey(CounterShardType name, int number) {
String id = String.format("%s%d", name, number);
return Datastore.createKey(CounterShard.class, id);
}

public static List getKeyList(CounterShardType name) {
List keys = new ArrayList();
for (int i = 0; i < name.getNumShards(); i++) {
keys.add(createKey(name, i + startKeyNumber));
}
return keys;
}
}

Google Code Archive - Long-term storage for Google Code Project Hosting.


import java.util.Map;

import org.slim3.datastore.Datastore;
import org.slim3.memcache.Memcache;
import org.smallreunion.meta.CounterShardMeta;
import org.smallreunion.model.CounterShard;
import org.smallreunion.model.constract.CounterShardType;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

public class CounterShardService {

CounterShardMeta meta = new CounterShardMeta();

public int getCount(CounterShardType name) {
if (Memcache.contains(name)) {
return Memcache.get(name);
}
int total = 0;
Map counterShards =
Datastore.getAsMap(meta, CounterShard.getKeyList(name));
for (CounterShard counterShard : counterShards.values()) {
total += counterShard.getCount();
}
return total;
}

public Key increment(CounterShardType name) {
Key key = CounterShard.createKey(name);

Transaction tx = Datastore.beginTransaction();
try {
CounterShard counter = Datastore.getOrNull(meta, key);
if (counter == null) {
counter = CounterShard.getInstance(name);
counter.setKey(key);
}
counter.increment();
Key result = Datastore.put(counter);
tx.commit();
incrementMemcache(name);
return result;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}

protected void incrementMemcache(CounterShardType name) {
if (!Memcache.contains(name)) {
return;
}
Memcache.increment(name, 1);
}
}

ちょっと例外時の処理とかが、まだ適当だったり・・・。
あおうさ殿がBlogに書かれているソースの方が、しっかり作ってありますので、そちらも見た方が良いです!
というか、あおうさ殿のBlogの方だけ見れば良いんじゃないかなと思いますw

AppEngineでCounterを実装する(2) #appengine #slim3 - あおうさ@日記