2012-05-21 13 views
8

Ho un disco esterno con un miliardo di file. Se monto il disco esterno nel computer A, il mio programma eseguirà la scansione del percorso di tutti i file e salverà il percorso dei file in una tabella del database. Dopodiché, quando espellisco il disco esterno, quei dati rimarranno nella tabella. Il problema è che se alcuni file vengono eliminati nel computer B e li monto nuovamente sul computer A, devo sincronizzare la tabella del database nel computer A. Tuttavia, non voglio scansionare nuovamente tutti i file perché ci vuole un sacco di tempo e sprecare un sacco di memoria. C'è un modo per aggiornare la tabella del database senza eseguire la scansione di tutti i file riducendo al minimo la memoria utilizzata?Gestire un gran numero di file

Inoltre, nel mio caso, la limitazione della memoria è più importante del tempo. Il che significa che preferirei risparmiare più memoria che risparmiare più tempo.

Penso di poter tagliare i file su molte sezioni e utilizzare una funzione specifica (potrebbe essere SHA1?) Per verificare se i file in questa sezione sono stati cancellati. Tuttavia, non riesco a trovare un modo per tagliare i file alle sezioni. Qualcuno può aiutarmi o darmi idee migliori?

+0

Elimina come in: eliminazione basata sul sistema su cui non si ha il controllo? o Un'eliminazione che è attivata da qualche applicazione in cui potresti fare qualcosa? – Krrose27

+0

Perché il processo di scansione utilizza molta memoria? In pratica stai semplicemente elencando i file in una directory alla volta, giusto? – Joni

+0

Sì, tuttavia, non riesco a controllare quanti file sono presenti nella directory. Una directory può contenere 1 miliardo di file. Inoltre, se inserisco un dato durante la scansione immediata di un file, esso risparmia molta memoria ma richiede molto tempo perché i problemi di I/O. Se uso l'inserto di massa, è più efficiente. – s011208

risposta

0

In teoria, è possibile velocizzare le cose controllando i timestamp "modificati" nelle directory. Se una directory non è stata modificata, non è necessario controllare alcun file in tale directory. Sfortunatamente, è necessario effettuare la scansione di eventuali sottodirectory e trovarle implica la scansione della directory ... a meno che non si sia salvata la struttura ad albero della directory.

E ovviamente, è ovvio che tu abbia una directory piatta contenente un miliardo di file.


Immagino che si sta assemblando tutti i filepaths in memoria in modo da poterli ordinare prima di interrogare il database. (E ordinarli è una buona idea ...) Tuttavia esiste un'alternativa all'ordinamento in memoria:

  1. Scrivere i percorsi di file in un file.
  2. Utilizzare un'utilità di ordinamento esterna per ordinare il file in ordine di chiave primaria.
  3. Leggere il file ordinato ed eseguire query batch sul database in ordine di chiave.

(Devi proprio un miliardo di file su un disco? Che suona come una cattiva progettazione per il tuo negozio di dati ...)

+0

Non metterò mai un miliardo di file in un disco esterno, è davvero un disastro; tuttavia, non posso promettere che tutti gli utenti non lo faranno. – s011208

+0

@ s011208 - beh, sarei propenso a dire agli utenti che è colpa loro se il tuo sistema impiega molto tempo quando inserisce un numero ridicolo di file sul disco. –

1

Se non si ha il controllo sul file system sul disco non hai altra scelta che scansionare i nomi dei file sull'intero disco. Per elencare i file che sono stati eliminati si potrebbe fare qualcosa di simile:

update files in database: set "seen on this scan" to false 
for each file on disk do: 
    insert/update database, setting "seen on this scan" to true 
done 
deleted files = select from files where "seen on this scan" = false 

Una soluzione al problema di prestazioni db potrebbe essere accumulando i nomi dei file in un elenco di qualche tipo e fare un inserimento/aggiornamento di massa ogni volta che si raggiungere, per esempio, 1000 file.

Per le directory con 1 miliardo di file, è sufficiente sostituire il codice che elenca i file con qualcosa che racchiude le funzioni C opendir e readdir. Se fossi in te non ti preoccuperei troppo per ora. Nessuna persona sana ha 1 miliardo di file in una directory perché quel genere di cose paralizza i file system e gli strumenti comuni del sistema operativo, quindi il rischio è basso e la soluzione è semplice.

+0

La tua soluzione è ciò che fa veramente il sistema Android! Ma il lato negativo di questa soluzione è che devi memorizzare l'attributo dei file nella memoria, ad esempio la mappa. Tuttavia, Android ha il limite di memoria! Quando hai solo 10 mila file, va bene. Se hai più di centomila file, il programma sarà costretto a terminare. Ora, proprio come la mia domanda, voglio trovare un modo per tagliare tutti i file del disco alle sezioni in modo che io possa fare una sezione in una sola volta ed evitare il problema di limitazione della memoria! – s011208

+1

Perché gli attributi dei file devono essere memorizzati nella RAM, ecco a cosa serve il database, giusto? O intendi l'elenco temporaneo utilizzato per l'inserimento di massa? È possibile scegliere la dimensione complessiva in modo dinamico in base alla memoria disponibile anziché utilizzare una dimensione fissa ... – Joni

0

Avete un elenco di cosa viene eliminato quando si verifica l'eliminazione (o si modifica qualsiasi processo di eliminazione per creare questo)?Se così fosse, non potresti avere un elenco di "Sono stato cancellato" con un timestamp, e quindi raccogliere gli elementi da questo elenco per sincronizzare solo ciò che è cambiato? Naturalmente, si vorrebbe comunque avere un qualche tipo di lavoro batch da sincronizzare durante un tempo lento sul server, ma penso che potrebbe ridurre il carico.

Un'altra opzione può essere, a seconda di cosa sta cambiando il codice, per fare in modo che quel processo aggiorni i database (se si hanno più nodi) direttamente quando si elimina. Ciò introdurrebbe qualche accoppiamento nei sistemi, ma sarebbe il modo più efficiente per farlo.

I modi migliori a mio avviso sono alcune variazioni sull'idea di messaggistica che si è verificata un'eliminazione (anche se si tratta solo di un file che si scrive in alcuni dove con un elenco di file eliminati di recente) o di qualche tipo di diretta meccanismo di callback, tramite il codice o semplicemente regolando l'archivio di dati persistente che l'applicazione utilizza direttamente dal processo di cancellazione.

Anche con tutto ciò detto, è sempre necessario avere un qualche tipo di sincronizzazione dell'indice o controllo periodico di integrità sugli indici per essere sicuri che tutto sia abbinato correttamente.

Si potrebbe (e sarei scioccato se non dovessi basare sul numero di file che hai) partizionare lo spazio file in cartelle con, ad esempio, 5.000-10.000 file per cartella, quindi creare un semplice file che ha un hash dei nomi di tutti i file nella cartella. Questo potrebbe catturare le eliminazioni, ma continuo a pensare che una richiamata diretta di qualche forma quando si verifica l'eliminazione sia un'idea molto migliore. Se hai una cartella monolitica con tutte queste cose, creare qualcosa per suddividerla in cartelle separate (abbiamo usato un numero semplice sotto la cartella principale in modo da poter andare avanti fino alla nausea) dovrebbe velocizzare tutto molto; anche se si deve fare questo per tutti i nuovi file e lasciare i vecchi file sul posto così com'è, almeno si potrebbe fermare il sanguinamento sul recupero dei file.

A mio parere, poiché si controlla a livello di codice un indice dei file, è necessario che lo stesso programma sia coinvolto in qualche modo (o notificato) quando si verificano cambiamenti al momento della modifica al file system sottostante, anziché consentire cambiamenti per accadere e quindi guardare attraverso tutto per gli aggiornamenti. Naturalmente, per catturare i valori anomali in cui questa comunicazione si interrompe, è necessario disporre anche del codice di sincronizzazione per verificare effettivamente ciò che si trova nel file system e aggiornare periodicamente l'indice (anche se questo potrebbe e probabilmente dovrebbe essere messo in batch fuori processo dall'applicazione principale)).

0

Se la memoria è importante, vorrei andare per le strutture del sistema operativo.

Se hai ext4 presumo che tu sia su Unix (puoi installare find su altri sistemi operativi come Win). Se questo è il caso, puoi usare il comando di ricerca nativo (questo sarebbe per l'ultimo minuto, puoi ovviamente ricordare l'ultima scansione e modificarlo in base alle tue preferenze): find/directory_path -type f -mtime -1 -print

Ovviamente non avrete le eliminazioni. Se un algoritmo euristico funziona per te, puoi creare un thread che va lentamente a ogni file memorizzato nel tuo database (qualunque cosa tu debba visualizzare prima, poi da nuovo a vecchio) e controllare che sia ancora online. Questo non consumerà molta memoria. Suppongo che non sarai in grado di mostrare comunque un miliardo di file all'utente.

Problemi correlati