2013-11-16 4 views
3

Я хочу один первичный набор элементов одного типа, которые сделаны с течением времени. Периодически несколько коллекций рабов собираются синхронизировать с первичной коллекцией. Первичная коллекция должна отправить дельта элементов в подчиненные коллекции.Эффективная структура данных и стратегия для синхронизации нескольких коллекций предметов

Primary Collection: A, C, D 
Slave Collection 1: A, C (add D) 
Slave Collection 2: A, B (add C, D; remove B) 

Подчиненные коллекции не могут добавлять или удалять элементы сами по себе, и они могут существовать в другом процессе, так что я, вероятно, будет использовать трубы, чтобы передать данные.

Я не хочу нажимать больше данных, чем необходимо, так как коллекция может стать довольно большой.

Какие структуры данных и стратегии были бы идеальными для этого?

+0

Является ли намерение привести рабов в согласие с мастером? Если да, то почему C удаляется из Slave 1? Если нет, то на каком основании мастер решил, что Slave 1 больше не нужен C? Если цель является конечной последовательностью, разве мастер просто не должен знать, что у каждого раба есть в коллекции? Как подчиненные будут сообщать мастеру, какую информацию они имеют в настоящее время? Как раб мог потерять (или получить) информацию, если они не могут добавлять или удалять предметы самостоятельно? Являются ли элементы изменчивыми? –

+0

@JonathanLeffler Yikes, это была ошибка. Да, цель состоит в том, что подчиненные должны отражать основную коллекцию и что мастер управляет тем, что находится в других коллекциях. Я должен был упомянуть, что коллекции подчиненных могут меняться в зависимости от того, когда подчиненный узел подключился к сети. – haste

ответ

1

Для этого я использую differential execution.

(кстати, слово «раб» неудобно для некоторых людей, с разумом.)

Для каждого удаленного сайта, есть последовательный файл на основном сайте, представляющее то, что существует на удаленном узле.

Существует процедура на основном сайте, проходящая через основную коллекцию, и по мере ее прохождения читает соответствующий файл, обнаруживая различия между существующим на удаленном сайте и тем, что должно существовать. Эти различия производят дельта, которые передаются на удаленный сайт. В то же время процедура записывает новый файл, представляющий, что будет существовать на удаленном сайте после обработки дельт.

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

В случае, если коллекции являются простыми списками вещей, это сводится к наличию локальных копий удаленных коллекций и выполнение алгоритма diff для получения дельта. Вот несколько таких алгоритмов:

Если коллекции могут быть отсортированы (например, ваш A, B, C пример), просто запустить цикл слияния:

while(ix<nx && iy<ny){ 
    if (X[ix] < Y[iy]){ 
    // X[ix] was inserted in X 
    ix++; 
    } else if (Y[iy] < X[ix]){ 
    // Y[iy] was deleted from X 
    iy++; 
    } else { 
    // the two elements are equal. skip them both; 
    ix++; iy++; 
    } 
} 
while(ix<nx){ 
    // X[ix] was inserted in X 
    ix++; 
} 
while(iy<ny>){ 
    // Y[iy] was deleted from X 
    iy++; 
} 

Если коллекции не могут быть отсортированы (примечание отношения к Levenshtein distance),

Until we have read through both collections X and Y, 
    See if the current items are equal 

    else see if a single item was inserted in X 
    else see if a single item was deleted from X 

    else see if 2 items were inserted in X 
    else see if a single item was replaced in X 
    else see if 2 items were deleted from X 

    else see if 3 items were inserted in X 
    else see if 2 items in X replaced 1 items in Y 
    else see if 1 items in X replaced 2 items in Y 
    else see if 3 items were deleted from X 

    etc. etc. up to some limit 

Производительность, как правило, не является проблемой, так как процедура не должна быть запущена на высокой частоте.

Есть crude video demonstrating this concept и source code where it is used for dynamically changing user interfaces.

1
  • Если вы не нажимаете на все данные, требуется сортировка журнала, который вместо использования пропускной способности канала использует основную память. Параметром для нахождения хорошего баланса между использованием памяти CPU & будет частота «push».
  • С вашего вопроса, я полагаю, у вас более одного подчиненного процесса. В этом случае некоторая разделяемая память или подход CMA (Linux) с двойной буферизацией в главном процессе должны превосходить многочисленные каналы на сегодняшний день, так как это даже не требует многопоточного нажатия, которое будет использоваться для оптимизации общей пропускной способности канала во время синхронизации.
    Ведомые процессы могут быть уведомлены с использованием глобального барьера синхронизации для чтения из masterCollectionA без копирования, тогда как мастер модифицирует masterCollectionB (который инициализируется копией из masterCollectionA) и наоборот. Доступ к коллекции должен быть заблокирован между подчиненными и ведущими. Ведомые могут копировать эту коллекцию (моментальный снимок), если они заблокируют ее после следующей попытки обновления с мастера, что позволит продолжить ее. Модификации в подчиненных процессах могут быть реализованы с копией стратегии записи для отдельных элементов. Этот совместный подход довольно прост для реализации, и в случае, если подчиненные процессы не копируют все снимки каждый раз, общее потребление памяти низкое.
Смежные вопросы