GAE + GWT プログラミングメモ

Google App Engine とGoogle Web Toolkit のメモ

Slim3のMemcacheを利用してDatastoreアクセスを少なくする その2

Slim3のMemcacheを利用してDatastoreアクセスを少なくする その1 - GAE + GWT プログラミングメモ
の続き

overwrite実装

上書き保存のための実装。
Slim3では、保存しようとしているKeyが既に存在する場合は、上書きする。

public class DataAccessor<T extends Slim3Model> {
    private DaoBase<T> dao;
    private KeyMemcache memcache = new KeyMemcache();

    public List<Key> overwrite(Collection<T> modelCollection) {
        Map<Key, T> map = new HashMap<Key, T>();
        for (T model : modelCollection) {
            map.put(model.getKey(), model);
        }
        memcache.putAll(map);
        return dao.put(new ArrayList<T>(modelCollection));
    }
}

dao.putするついでに、memcache.putAllして、Memcacheに保存し、次回アクセスを速くする。

write実装

writeはDatastoreに既にKeyが存在する場合、上書きしたくないときのための実装。

public class DataAccessor<T extends Slim3Model> {
    public List<Key> write(Collection<T> modelCollection) {
        List<T> storedList = read(toKeyList(modelCollection));
        Collection<T> subtract =
            CollectionUtils.subtract(modelCollection, storedList);
        return overwrite(subtract);
    }

    private List<Key> toKeyList(Collection<T> modelCollection) {
        List<Key> keyList = new ArrayList<Key>();
        for (T model : modelCollection) {
            keyList.add(model.getKey());
        }
        return keyList;
    }
}

readで保存してあるListを取得し、書き込もうとしている集合との差集合subtractをとる。
この差集合のみoverwriteする。

全実装

public class DataAccessor<T extends Slim3Model> {
    private DaoBase<T> dao;
    private KeyMemcache memcache = new KeyMemcache();

    public DataAccessor(DaoBase<T> dao) {
        this.dao = dao;
    }

    public T read(Key key) {
        List<Key> keyList = new ArrayList<Key>();
        keyList.add(key);
        return read(keyList).get(0);
    }

    public List<T> read(List<Key> keyList) {
        Map<Key, T> memcachedModelMap = memcache.getAll(keyList);
        Map<Key, T> daoModelMap = getDaoModelMap(keyList, memcachedModelMap);
        memcache.putAll(daoModelMap);

        List<T> modelList = new ArrayList<T>();
        for (Key key : keyList) {
            if (memcachedModelMap.containsKey(key)) {
                modelList.add(memcachedModelMap.get(key));
            } else if (daoModelMap.containsKey(key)) {
                modelList.add(daoModelMap.get(key));
            }
        }
        return modelList;
    }

    private Map<Key, T> getDaoModelMap(List<Key> keyList, Map<Key, T> memcachedModelMap) {
        Collection<Key> subtractedCollection =
            CollectionUtils.subtract(keyList, memcachedModelMap.keySet());
        List<Key> subtractedList = new ArrayList<Key>(subtractedCollection);
        return dao.getAsMap(subtractedList);
    }

    public List<Key> overwrite(Collection<T> modelCollection) {
        Map<Key, T> map = new HashMap<Key, T>();
        for (T model : modelCollection) {
            map.put(model.getKey(), model);
        }
        memcache.putAll(map);
        return dao.put(new ArrayList<T>(modelCollection));
    }

    public List<Key> write(Collection<T> modelCollection) {
        List<T> storedList = read(toKeyList(modelCollection));
        Collection<T> subtract =
            CollectionUtils.subtract(modelCollection, storedList);
        return overwrite(subtract);
    }

    private List<Key> toKeyList(Collection<T> modelCollection) {
        List<Key> keyList = new ArrayList<Key>();
        for (T model : modelCollection) {
            keyList.add(model.getKey());
        }
        return keyList;
    }
    
    private class KeyMemcache {
        public void putAll(Map<Key, T> values) {
            Map<Object, Object> objectMap = new HashMap<Object, Object>();
            for (Entry<Key, T> entry : values.entrySet()) {
                Object key = entry.getKey();
                Object model = entry.getValue();
                objectMap.put(key, model);
            }
            Memcache.putAll(objectMap);
        }
        public Map<Key, T> getAll(List<Key> keyList) {
            Map<Key, T> map = new HashMap<Key, T>();
            Map<Object, Object> memcachedMap = Memcache.getAll(keyList);
            for (Entry<Object, Object> entry : memcachedMap.entrySet()) {
                Key key = (Key) entry.getKey();
                @SuppressWarnings("unchecked")
                T model = (T) entry.getValue();
                map.put(key, model);
            }
            return map;
        }
    }
}