SimpleDB でカウンターを実装する

SimpleDB では、autoincrement のような採番の機構は用意されていないため、ユニークなカウンターを利用したい場合は以下のようになります。ポイントとしては UpdateCondition で排他処理を行って、GET/PUT の合間に別の処理が割り込んできたら検知できるようにします。

  public Integer counter(String domain) {
    AmazonSimpleDB client = getClient();
    GetAttributesRequest getAttributesRequest = new GetAttributesRequest();
    getAttributesRequest.setDomainName("__counter");
    getAttributesRequest.setItemName(domain);
    getAttributesRequest.setConsistentRead(true);
    Integer count = null;
    try {
      GetAttributesResult attributes =
        client.getAttributes(getAttributesRequest);
      List<Attribute> list = attributes.getAttributes();
      for (Attribute item : list) {
        if ("c".equals(item.getName())) {
          try {
            count = Integer.valueOf(item.getValue());
          } catch (Throwable ignore) {

          }
        }
      }
    } catch (Throwable t) {
      t.printStackTrace();
    }

    if (count == null) {
      CreateDomainRequest createDomainRequest =
        new CreateDomainRequest("__counter");
      client.createDomain(createDomainRequest);
      count = 0;
    }

    int next = count + 1;
    PutAttributesRequest putAttributesRequest = new PutAttributesRequest();
    putAttributesRequest.setDomainName("__counter");
    putAttributesRequest.setItemName(domain);
    List<ReplaceableAttribute> attr = new ArrayList<ReplaceableAttribute>();
    attr.add(new ReplaceableAttribute("c", String.valueOf(next), true));
    putAttributesRequest.setAttributes(attr);
    UpdateCondition updateCondition = new UpdateCondition();
    if (next == 1) {
      updateCondition.setExists(false);
      updateCondition.setName("c");
    } else {
      updateCondition.setExists(true);
      updateCondition.setName("c");
      updateCondition.setValue(String.valueOf(count));
    }
    putAttributesRequest.setExpected(updateCondition);

    client.putAttributes(putAttributesRequest);

    return next;
  }