предотвратить конфликт с spymemcached

Я пытаюсь использовать spymemcached 2.6 с синхронизацией при обновлении и нашел два следующих способа его использования:

  • используя CASMutation, определяющий CASMutator, который является довольно инвазивным способом его реализации, давайте посмотрим на пример:

    public List<Item> addAnItem(final Item newItem) throws Exception {
    
        // This is how we modify a list when we find one in the cache.
        CASMutation<List<Item>> mutation = new CASMutation<List<Item>>() {
    
            // This is only invoked when a value actually exists.
            public List<Item> getNewValue(List<Item> current) {
                // Not strictly necessary if you specify the storage as
                // LinkedList (our initial value isn't), but I like to keep
                // things functional anyway, so I'm going to copy this list
                // first.
                LinkedList<Item> ll = new LinkedList<Item>(current);
    
                // If the list is already "full", pop one off the end.
                if(ll.size() > 10) {
                    ll.removeLast();
                }
                // Add mine first.
                ll.addFirst(newItem);
    
                return ll;
            }
        };
    
        // The initial value -- only used when there's no list stored under
        // the key.
        List<Item> initialValue=Collections.singletonList(newItem);
    
        // The mutator who'll do all the low-level stuff.
        CASMutator<List<Item>> mutator = new CASMutator<List<Item>>(client, transcoder);
    
        // This returns whatever value was successfully stored within the
        // cache -- either the initial list as above, or a mutated existing
        // one
        return mutator.cas("myKey", initialValue, 0, mutation);
    }
    

или с помощью метода cas

cas(String key, long casId, Object value)

после того, как сделал:

gets(String key, Transcoder<T> tc) 

Второй действительно более простой, и я понимаю, почему я буду использовать CASMutation... Мне было бы очень приятно получить отзывы об использовании этого клиента кушетки.


person terry    schedule 15.06.2011    source источник


Ответы (1)


CASMutator/CASMutation собирает лучшие практики и рабочий процесс, чтобы все было сделано для вас правильно.

Ваш контрпример выглядит более простым, поскольку вы не говорите, что на самом деле делаете с этими методами. Пример, который вы разместили выше, показывает, что список извлекается из memcached, к нему добавляется новый элемент, условно удаляются некоторые элементы из него, а затем возвращается. По крайней мере, половину того текста, который вы разместили, вам еще нужно написать.

Если вы не будете использовать CASMutator, вы в конечном итоге изобретете его заново, а это не так просто. Вот что он делает для вас сегодня:

public T cas(final String key, final T initial, int initialExp,
        final CASMutation<T> m) throws Exception {
    T rv=initial;

    boolean done=false;
    for(int i=0; !done && i<max; i++) {
        CASValue<T> casval=client.gets(key, transcoder);
        T current=null;
        // If there were a CAS value, check to see if it's compatible.
        if(casval != null) {
            T tmp = casval.getValue();
            current=tmp;
        }
        // If we have anything mutate and CAS, else add.
        if(current != null) {
            // Declaring this impossible since the only way current can
            // be non-null is if casval was set.
            assert casval != null : "casval was null with a current value";

            rv=m.getNewValue(current);
            // There are three possibilities here:
            //  1) It worked and we're done.
            //  2) It collided and we need to reload and try again.
            //  3) It disappeared between our fetch and our cas.
            // We're ignoring #3 because it's *extremely* unlikely and the
            // behavior will be fine in this code -- we'll do another gets
            // and follow it up with either an add or another cas depending
            // on whether it exists the next time.
            if(client.cas(key, casval.getCas(), rv, transcoder)
                    == CASResponse.OK) {
                done=true;
            }
        } else {
            // No value found, try an add.
            if(initial == null) {
                done = true;
                rv = null;
            } else if(client.add(key, initialExp, initial, transcoder).get()) {
                done=true;
                rv=initial;
            }
        }
    }
    if(!done) {
        throw new RuntimeException("Couldn't get a CAS in " + max
            + " attempts");
    }

    return rv;
}
person Dustin    schedule 15.06.2011
comment
хорошо, вы совершенно правы, но вам не кажется, что это решение довольно навязчиво? - person terry; 16.06.2011
comment
Навязчивый в каком смысле? Он смоделирован на основе операций CAS на процессорах и должен довольно хорошо масштабироваться, за исключением мест с высокой конкуренцией за один ключ. Честно говоря, Java делает это немного сложнее. Большая часть кода представляет собой простое лямбда-выражение на многих языках. Java просто предлагает кучу синтаксиса, чтобы обернуть его. - person Dustin; 16.06.2011
comment
мне это кажется навязчивым, потому что я должен поместить свой бизнес-код в определение функции spymemcached getNewValue. Вам не кажется, что использование каких-то узоров или разделительного слоя было бы невозможно? - person terry; 17.06.2011
comment
Это это другой слой. Вы должны быть более конкретными в отношении того, что вы хотите, чтобы это преобразование делало, но что бы вы ни хотели сделать, вы просто заставляете клиента делать это ближе к серверу, или вы делаете это вручную и просто выполняете больше работы над вне. Вам доступно все возможное, но я не знаю, что вы считаете менее навязчивым. - person Dustin; 20.06.2011