elegxos an ena file einai anoikto

Giorgos Keramidas keramida at ceid.upatras.gr
Sun Feb 23 03:30:02 EET 2003


On 2003-02-21 14:18, tc <tasosc at otenet.gr> wrote:
> Γράφω ένα πρόγραμμα που μία από τις δουλείες του είναι να διαβάζει
> αρχεία από ένα υποκατάλογο και να τα διαγράφει.  Το πρόβλημα που έχω
> είναι ότι τα αρχεία αυτά μπορεί να μην μεταφέρονται στον υποκατάλογο
> αυτο ατομικά (π.χ. με rename) αλλά να αντιγράφονται μη ατομικά π.χ.
> fopen while  fwrite ktl

Λογική σκέψη.

> Πρώτη σκέψη που έκανα ήταν να τα κάνω rename σε κάποιο άλλο κατάλογο
> στο ίδιο fs πρότού αρχίσει το πρόγραμμα μου τα ανοίξει και τα
> διαβάζει.  Ξέρει κανείς αν αυτος ο τρόπος είναι ασφαλες σε solaris,
> linux, *bsd κτλ σε τοπικό fs ή σε nfs ; (Ασφαλές εννόω να είναι
> πλήρες το αρχείο).

Αν έχεις έλεγχο στον κώδικα του προγράμματος που αντιγράφει τα αρχεία,
τότε διάβασε το manpage της flock(2) και προσπάθησε να κλειδώνεις το
αρχείο με advisory locks κατά τη δημιουργία του.  Όταν κάνεις scan τον
κατάλογο με opendir(); while (readdir()) { ...; } closedir(); βάλε
ελέγχους για advisory locks στο κάθε αρχείο, και αν είναι κλειδωμένο
ακόμα από κάποια process υλοποίησε κάποιο exponential backoff
αλγόριθμο που θα ξαναδοκιμάζει αργότερα, και στο τέλος όταν το backoff
timeout φτάσει κάποιο maximum θα θεωρεί πως το process που έκανε το
flock(2) αρχικά έχει πλέον πεθάνει.

Μπορείς π.χ. να κάνεις κάτι σαν:

	opendir();
	while (readdir()) {
		if (file is locked)
			add_to(locked_list);
		else
			run_file();
	}
	closedir();

	timeout_locked(locked_list);

Ένας αρκετά έξυπνος timeout αλγόριθμος μπορεί να υλοποιηθεί με ένα
usleep() loop, που θα μειώνει κατά ένα το timecounter για κάθε αρχείο
της locked_list.   Αρχικά τα αρχεία προστίθενται στην locked_list με
προκαθορισμένο timeout = k ticks.  Κάθε φορά που ένα αρχείο φτάνει να
έχει tc = 0, δοκιμάζεις να δεις αν ξεκλείδωσε.  Αν όχι, διπλασιάζεις
το προηγούμενο tc του και το αφήνεις στη λίστα.  Αν το tc φτάσει να
έχει τιμή max_tc, κάθε φορά που γίνεται μηδέν αυξάνεις ένα μετρητή.
Αν ο μετρητής των timeouts με tc = maxtc ενός αρχείου φτάσει μια
μέγιστη τιμή, απλά θεωρείς πως έχει ψοφήσει το process που είχε το
advisory lock και σβήνεις το αρχείο.

===== Ενδεικτική ψευδο-υλοποίηση =====

	#define	DELETE_MAYBE	0	/* check flock() before deleting */
	#define	DELETE_FORCE	1	/* unconditionally delete file */

	#define FI_LMAX		100 	/* maximum allowed tclast */
	#define	FI_TOMAX	10	/* max LMAX hits */

	struct file_info {
		int	fi_tc;			/* current tc */
		int	fi_tclast;		/* last !0 tc */
		int	fi_hits;		/* times we have hit FI_LMAX */

		char	*fi_path;		/* pathname of file */

		struct file_info *fi_prev;	/* List junk :P */
		struct file_info *fi_next;
	};

	void
	timeout_locked(struct file_info **lf)
	{
		struct file_info *f;

		if (lf == NULL)
			return;

		while (1) {
			/* No more files left on the list. */
			if (*lp == NULL)
				return;

			/* Run through `lp' and update counters. */
			for (f  = *lf; f != *lf; f = f->fi_next) {
				if (f->fi_tc > 0)
					f->fi_tc--;
				/*
				 * Count how many times we have timed out from
				 * a FI_LMAX initial value.
				 */
				if (f->fi_tc == 0 && f->fi_tclast == FI_LMAX)
					f->fi_hits++;
				/*
				 * Too many timeouts on FI_LMAX.
				 * Unconditionnally delete file.
				 */
				if (f->fi_hits >= FI_TOMAX)
					delfile(f, DELETE_FORCE);
				/*
				 * All other timeouts double f->fi_tclast and
				 * start another waiting round for the current file.
				 */
				if (f->fi_tc == 0)
					if (delfile(f, DELETE_MAYBE) == -1) {
						if (f->fi_tclast <= FI_LMAX) {
							f->fi_tclast <<= 1;
							f->fi_tc = f->fi_tclast;
						}
					} else {
						/*
						 * File was removed.
						 * Remove it from `lp' list.
						 */
					}
				}
			}

			/* Sleep until next iteration. */
			usleep(20000);
		}
	}

	int
	delfile(struct file_info *f, int force)
	{
		if (f == NULL)
			return 0;

		if (force) {
			if (f->fi_path != NULL)
				unlink(f->fi_path);
			return 0;
		}

		/* Check with flock, and return -1 if still locked. */
		/* Delete file otherwise, and return 0. */
	}




More information about the Linux-greek-users mailing list