Основываясь на ваших наблюдениях, я посмотрел на реализацию C * модели кэширования APC (apc_cache.c
), чтобы увидеть, что я смог найти.
Источник подтверждает ваши наблюдения о том, что в резервном хранилище данных не существует структуры группировки, так что любую свободно-сгруппированную коллекцию объектов необходимо будет делать на основе некоторого ограничения пространства имен или модификации самого уровня кэша.Я надеялся найти какой-нибудь бэкдор, опирающийся на связывание ключей посредством связанного списка, но, к сожалению, кажется, что коллизии примиряются путем прямого перераспределения сталкивающегося слота вместо цепочки .
Еще больше запутывая эту проблему, APC, похоже, использует явную модель кэша для записей пользователей, предотвращая их устаревание.Итак, решение, предоставленное Эмилем Викстремом , основанное на модели LRU memcached , к сожалению, не будет работать.
Без изменения источникакод самого APC, вот что я бы сделал:
Определите ограничение пространства имен, которому соответствуют ваши записи.Как вы изначально определили выше, это будет что-то вроде article_
с добавлением к каждой из ваших записей.
Определите отдельный список элементов в этом наборе,По сути, это будет схема 5
, 10
и 17
, которую вы описали выше, но в этом случае вы можете использовать некоторый числовой тип, чтобы сделать это более эффективным, чем хранение большого количества строковых значений.
Определить интерфейс для обновления этого набора указателей и согласования их с резервной кэш-памятью, включая (как минимум) методы insert
, delete
и clear
.Когда вызывается clear
, пройдитесь по каждому из ваших указателей, восстановите ключ, который вы использовали в хранилище резервных данных, и очистите каждый из вашего кеша.
То, что я защищаю здесьявляется четко определенным объектом, который выполняет операции, которые вы ищете эффективно .Это линейно масштабируется с количеством записей в вашем дополнительном кэше, но поскольку вы используете числовой тип для каждого элемента, вам потребуется более 100 миллионов записей или около того, прежде чем вы начнете испытывать реальную боль в памяти при ограничении,например, несколько сотен мегабайт.
Тамас Имрей побил меня до , предлагая альтернативную стратегию Я уже находился в процессе документирования, но в этом есть некоторые серьезные недостатки, которые янравится обсуждать.
Как определено в базовом коде C, APCIterator
- это линейная операция времени над полным набором данных при выполнении поиска (с использованием его конструктора).public __construct ( string $cache [, mixed $search = null ...]] )
).
Это категорически нежелательно в том случае, когда искомые элементы, которые вы ищете, представляют небольшой процент от ваших общих данных, потому что каждый элемент в вашем кэше будет проходить, чтобы найти те, которые вы желаете.Ссылаясь на apc_cache.c
:
/* {{{ apc_cache_user_find */
apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, \
int keylen, time_t t TSRMLS_DC)
{
slot_t** slot;
...
slot = &cache->slots[h % cache->num_slots];
while (*slot) {
...
slot = &(*slot)->next;
}
}
Поэтому я настоятельно рекомендую использовать эффективное решение для виртуальной группировки на основе указателей для вашей проблемы, как я набросал выше.Хотя в случае, когда у вас серьезные ограничения памяти, итераторский подход может быть наиболее правильным, чтобы сохранить как можно больше памяти за счет вычислений.
Удачи в вашем приложении.