Предполагая адреса IPv4, пространство поиска составляет 2 32 . Вам нужно не более 1 бита на IP-адрес (0 == нет посещения, 1 == посещение). Без учета накладных расходов на хранение потребуется 512 МБ (2 29 ) для хранения. Таким образом, упрощенная реализация будет выделять массив размером 512 МБ (или таблицу с 2 29 строками, каждая из которых хранит байт, или 2 27 строками, каждая из которых хранит 32-разрядное целое число, или 2 26 строк, каждая из которых хранит 64-разрядное целое число, или ...)
Вы можете оптимизировать это для разреженного населения, превратив его в дерево.
Определить размер "страницы" в 2 x бит. Вы будете выделять хранилище для одной страницы за раз.
Разделите область поиска (2 32 ) на размер страницы. Это общее количество страниц, необходимое для представления каждого возможного адреса в вашем пространстве поиска.
Затем, чтобы определить, есть ли совпадение в вашем хэше, вы сначала определите, присутствует ли страница, и если да, установлен ли соответствующий бит на странице. Чтобы кэшировать адрес, вы сначала определите, присутствует ли страница; если нет, вы создадите его. Далее вы установите соответствующий бит.
Это довольно легко превращается в таблицу базы данных. Вам потребуется всего два столбца: индекс страницы и двоичный массив. Когда вы выделяете страницу, вы просто сохраняете строку в таблице с правильным индексом страницы и пустым двоичным массивом.
Например, для 1024-битного размера страницы (получая максимум 2 22 * 1030 * страниц) вы можете структурировать таблицу следующим образом:
CREATE TABLE VisitedIPs(
PageIndex int NOT NULL PRIMARY KEY,
PageData binary(128) NOT NULL
)
Чтобы проверить, посещал ли IP-адрес, вы должны использовать код, подобный (псевдокод):
uint ip = address.To32Bit();
string sql =
"SELECT PageData " +
"FROM VisitedIPs " +
"WHERE PageIndex = " + (ip >> 10);
byte[] page = (byte[])GetFromDB(sql);
byte b = page[(ip & 0x3FF) >> 3];
bool hasVisited = (b & (1 << (ip & 7)) != 0;
Настройка посещения IP-адреса аналогична:
uint ip = address.To32Bit();
string sql =
"SELECT PageData " +
"FROM VisitedIPs " +
"WHERE PageIndex = " + (ip >> 10);
byte[] page = (byte[])GetFromDB(sql);
page[(ip & 0x3FF) >> 3] |= (1 << (ip & 7));
sql =
"UPDATE VisitedIPs " +
"SET PageData = @pageData " +
"WHERE PageIndex = " + (ip >> 10);
ExecSQL(sql, new SqlParam("@pageData", page));