A sincronização necessária é algum sistema de locking para os índices de
cache. Os clientes estão requisitando informação dele, enquanto o
crawler está alimentando ele com informações.
Para evitar que o índice seja corrompido, o crawler deve bloquear as
áreas do índice em que ele vai modificar / adicionar ou remover
entradas ;)
Sobre send e recv, eles ocorrem em duas partes deste sistema;
1) Browser <---> WebServer (durante pesquisa)
2) Crawler <---> WebServer (durante indexação)
Facilitou ou dificultou mais? oO
Abraço,
Sérgio
A questão não é acessar um índice inválido, a questão é a
possibilidade do crawler estar alterando ou removendo um dando ao
mesmo tempo que o sistema de query está utilizando ele.
Imagine, por algum motivo, que a remoção de um ínidice sempre zera
todos os dados da entrada para invalidá-la. Vamos supor que na
estrutura proposta tenha os seguintes dados:
id,url,titulo_url,ultima_visita (todos de tamanho fixo)
Caso hipotético que demonstre a necessidade do lock:
1) O cliente via web browser solicita uma busca pela palavra foo
2) O servidor web inicia a query
3) A query inicia a leitura da entrada id 12312 que é originalmente
para a url http://www.tchelinux.org/foo; A leitura é interrompida na
CPU com buffer insuficiente para ler todos os dados. Digamos que tenha
sido lido "http://ww"; Há a troca de contexto
4) O crawler invalida a entrada 12312 e tem tempo suficiente (em cpu e
disco) para zerar todos os campos
5) A query volta para a cpu e faz nova(s) solicitaçõe(s) de leitura e
termina por ter lido uma entrada corrompida, pois o "titulo_url"
estará em branco e a "url" estará truncada
Porém, em termos de banco de dados, concordo com você plenamente. Em
geral os índices e entradas nos bancos tem uma flag que indica se este
é válido ou não, onde um poderia estar requisitando os dados e o outro
invalidando eles ao mesmo tempo, que não haveria problema.
O problema todo gira em torno da concorrência de uso da CPU pelos
processos rodando na máquina servidora. Não sei se você já passou por
cadeiras de SO, caso não, seu professor deveria ter dado uma explicada
como +/- funciona o sistema de processos (ou tarefas) e threads antes
entrar na parte de sincronização em sí.
Vou tentar escrever uma breve explicação sobre isso.
Primeiramente o contexto de execução. Cada processo rodando no sistema
operacional tem um contexto, o qual é responsável por guardar
informações sobre o processo. Informações como última instrução
executada, área(s) de memória alocada, arquivo(s) aberto(s),
bibliotecas compartilhadas, usuário que está rodando, etc...
Os sistemas operacionais modernos suportam a execução de diversos
processos de forma "paralela", onde para cada processo existe um
contexto associado. A palavra paralelo está entre áspas pois apenas em
algumas situações (máquinas multi-processadas e/ou multi-núcleos)
realmente exite processamento paralelo. Para que o sistema operacional
dê essa idéia de paralelismo, ele implementa o modelo de "time
sharing", onde é dada uma pequena fatia de tempo para cada processo
executar na CPU.
Quando um processo tem seu tempo de execução finalizado, ele é
retirado da CPU, seu contexto é gravado na memória e o kernel coloca
outro processo na CPU, restaurando o contexto previamente salvo. Este
procedimento é chamado de troca de contexto e ocorre milhares de vezes
em apenas um segundo, para se ter uma idéia de como é pequena a
"fatia" de tempo.
Uma troca de contexto pode ocorrer em quase qualquer parte de
execução* do seu código fonte, ou seja, a última instrução executada
pelo seu programa pode ser um "fread", como no exemplo do email
anterior, quando o kernel tirou ele da CPU e colocou outro processo.
Caso este outro processo esteja modificando o mesmo arquivo que o
processo que acaba de ser removido da CPU, pode ocorrer o truncamento
das informações, como no exemplo do email anterior.
Assim dá para definir que em quase qualquer recurso que possa ser
compartilhado (memória, disco, conexões de rede, etc...) entre
processos ou threads, se faz necessário algum modelo de sincronização.
Para o caso salientado pelo Rafael (atualização dos dados), você
sempre está sujeito a corrompimento dos dados, pois você estará
modificando um dado "ao mesmo"** tempo que outro processo pode estar
lendo ou escrevendo neste dado.
* Existem execuções de código que são atômicos, onde mesmo que o tempo
do processo tenha acabado, o kernel somente irá tirar ele da CPU
quando terminar a execução, logo, entende-se que estas execuções devem
ser pequenas e rápidas, evitando que o S.O. dê "umas trancadas".
** Conforme explicado, não é exatamente ao mesmo tempo, e sim, entre
trocas de contexto. Para computadores multi-processador e/ou
multi-core, dependendo do recurso é permida leitura e/ou escrita
concorrente. Caso não seja, o kernel ou o próprio recurso tratam a
leitura e/ou escrita concorrente, para processos rodando em CPUs
diferentes.
Abraço,
Sérgio