Chtěl jsem říct ne mysql lite ale sqlite. Ale z databázemi jsem moc nepracoval takže je nemám v malíčku, takže ty jak to třeba popisuješ pro tebe by to nebyl problém. ...
Ten problém je skutečně triviální, jeden sloupec, jeden index. To by jsi určitě zvládl.
Mě každopádně láká ta možnost napsat vlastní třídu a vyzkoušet něco jak by to bylo nebo nebylo efektivní...
A já to tak taky vnímám...
... (spíš si myslím, že je to řešení psané na míru).
Na míru čeho? Bude mít ta množina IP adres nějakou charakteristiku nebo nějaká vyplývá z toho, že to budou proxy servery? Já jsem tam nic speciálního neviděl, ten problém se mi jeví jako zcela obecné vyhledávání v množině čísel.
Tak zase z mého úhlu pohledu. IP adresa sice může obsahovat nuly, ale mám pocit, že toto platí jen v místní síti. Na veřejné síti se nuly neobjevují. Takže máš pravdu, že adresa vnitřní sítě např. 127.0.0.1 má jako první bajt 127, ale posuzuju podle druhého bajtu, který je 0 a tudíž by opravdu došlo k chybě. Nicméně, počítám s tím že tyto adresy tam prostě nebudou. Počítám, že zapisuji proxy adresy, ale připomínka je to dobrá. Tzn. co bych tam měl zapsat místo nuly, 255 do celého souboru?
Ne, když se pro jednoduchost budeme zabývat jen druhým nejvýznamnějším bajtem, tak jakákoliv hodnota včetně 0 či 255 může být součástí veřejné IP adresy koncového zařízení.
Co se týče adres, které mají v druhém bajtu 0 a se kterými nemusíš počítat, tak jsou IMHO následující:
- 127.0.x.x - část rozsahu 127.x.x.x pro loopback
- 10.0.x.x - lokální síť třídy A
- [>=224].0.x.x - multicast a část rezervovaného rozsahu [240-255].x.x.x
- broadcast pro každou síť, který má v bitech pro hosta samé jedničky (nejvyšší adresa v síti), např. x.0.0.255 (broadcast sítí třídy A)
- samotné adresy sítí, tj. ne koncových zařízení, které mají v bitech pro hosta samé nuly (nejnižší adresa v síti), např. x.0.0.0 - adresy všech sítí třídy A
Co ale s tím?
Takže tabulku klidně inicializovat nulama můžeš, ale aby jsi našel konec dat (první prázdný záznam), musíš kontroloval, zda jsou v tabulce nuly na pozicích všech bajtů záznamu IP adresy, protože máš záznam rozdělen na 3 bajty. Potom by mohly záznamy kolidovat jen s adresami sítí třídy A (x.0.0.0), protože hodnota 1. bajtu ti data rozděluje na segmenty, ale adresy sítí tam nebudou. Nejlepší je stejně ukládat si počet záznamů, a potom nemusíš vůbec hledat konec, budeš ho vždy znát: začátek segmentu + počet záznamů * (1 bajt).
Další věc je ta, že po zaplnění tabulky ji vyprázdníš, tudíž ztratíš informace o všech blokovaných IP adresách a začneš znovu. To asi není, to co bys chtěl. Co tam bude ty blokované IP adresy přidávat? Ideální je uchovávat si časy posledního "zásahu" pro každou blokovanou adresu a pokud ti dojde místo, nahradit ten záznam, který měl zásah před nejdelší dobou. Případně to kombinovat s četnosti záznamů apod. Triviální pro databázi (druhé pole, druhý index) nebo vytvořit druhý binární strom.
Pokud jde o konec metody checkIP tak tam je to takto:
if(...){...}
else
{ return true; // no more ips to check
}
endfor;
echo " end of check method ";
return true;
}
Tobě jde o to, že fread($hf,1) volám ze smyčky místo fread($hf,250) bez smyčky? ...
Psal jsem "smyčka se přeruší při prvním bajtu, který nedopovídá druhému bajtu IP adresy a tedy téměř vždy skončí bez vrácení hodnoty".
public function checkIP ($ip)
{
$arr = $this->splitIp($ip);
$segmentBegin = ($arr[0] - 1) * $this->segmentLength;
if (! $this->FRWBHandler)
$this->FRWBHandler = @fopen($this->file, "r+b");
$fh = & $this->FRWBHandler;
for ($i = $segmentBegin; $i <= $segmentBegin + $this->segmentLength; $i ++) :
fseek($fh, $i);
$byte = fread($fh, 1);
if ($byte !== "\x00") {
if ($byte === "\x" . $arr[1]) {
fseek($fh, $i + $this->segmentLength);
$byte = fread($fh, 2);
if ($byte === "\x" . $arr[2]) {
fseek($fh, $i + 2 * $this->segmentLength);
$byte = fread($fh, 1);
if ($byte === "\x" . $arr[3])
return false; // this ip is blocked
}
}
break;
} else
return true; // no more ips to check
endfor
;
}
Špatně je ten "break", místo něho musí být "continue" a také to, že za smyčkou nevracíš true (to už jsi tam doplnil).
Ale abys ošetřil ty případné nuly v IP adresách, tak by jsi musel v každém průchodu kontrolovat všechny 3 bajty IP adresy.
Dále píšeš o režii databáze, jasně to se musí brát v úvahu, proto jsem psal "Pokud chceš udělat něco co bude efektivnější než databáze". Ale ta režie není závislá na velikosti souboru, algoritmu vyhledávání, ale spíš jak jsi psal na komunikaci mezi skriptem a databázovým serverem. Určitě to lze implementovat s menší režií bez databáze. Ta sqlite vypadá pro tenhle účel zajímavě. Defakto ti ale stačí implementovat binární strom.
Mám pocit, že jsi jednou psal, že zkoušíš udělat optimální algoritmus, jindy že ti rychlost postačuje. Kdyby jsi do jednoho souboru ukládal 250 x 32bit číslo jako IP adresu a při každém testu procházel vše, nemohlo by to být pomalejší než to máš teď. To rozdělování IP adresy na jednotlivé bajty a jejich ukládání do zvláštních segmentů nemá ve tvé implementaci téměř žádný smysl, musíš stejně otestovat všech 250 záznamů. Výjimkou je pouze ten první bajt, který neukládáš, ale určuje ti segment, ale zase ti kvůli tomu narostla velikost dat 256x.
Kdyby jsi byl důsledný, a udělal to i pro ostatní komponenty IP adresy, tak máš vlastně pole o 4 rozměrech, bitmapu o 222(?)*256*256*254 záznamech pro kompletní rozsah IP adres, tj. soubor o velikost 440MiB, tam by jsi skutečně nemusel nic hledat, a vždy by jsi přečetl nebo zapsal pouze 4 bity. Nevýhoda - veliký soubor zabírající místo na disku, nic efektivnějšího nelze ale vymyslet. Buď tedy tohle, nebo chceš mít uložen jen omezený počet IP adres a potom musíš mít seznam setříděn nebo uložen v binárním stromu. Záleží na tom kolik těch IP adres bude, a jak často se budou zapisovat, protože při zápisu musíš záznamy setřídit nebo rebalancovat strom. Budeš-li mít záznamy setříděné nebo v úplném binárním stromu, potřebuješ ke zjištění, zda IP adresa NENÍ přítomna v 250 záznamech MAXIMÁLNĚ 8 testů. Ty jich potřebuješ VŽDY 250 * 3, takže 750. Použití prvního bajtu IP adresy jako čísla segmentu ti to zredukovalo na 750 z 1000 testů ale 256x ti narostla velikost tabulky. Obě možností můžeš kombinovat a hledat kompromis mezi rychlostí a potřebnou velikostí tabulky, ale pokud se bude jednat víceméně o náhodné IP adresy, tak nemáš podle čeho optimalizovat.
Navíc kromě té kompletní bitmapy má sotva smysl ukládat komponenty IP adresy zvlášt - převeď ji na 32bit číslo.