navwin » Tech Talk » Beyond the Basics » Reading Directory Listings
Beyond the Basics
Post A Reply Post New Topic Reading Directory Listings Go to Previous / Newer Topic Back to Topic List Go to Next / Older Topic
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration

0 posted 2002-11-17 10:12 PM



Ok - doing fairly well based on the last set ( /pip/Forum65/HTML/000013.html ) though i haven't touched everything in there (like the email file, which i can see being necessary) and would like to see if i can ask about what i FEEL is the next step (because it might not be, lol).

I have it now where i can set a specific ID (so to speak) number, create a directory and file based off of that, containing the 'pertinent' information.

however, lol, i don't think it would be feasible to assign everyone the same id number. *grin* so what i'm curious about is how i can set it up to advance a number for each addition, based on what exists at the time of submission. (understanding that i will want another part to check if the submission is an existing member - i think i can handle this part and will address it later).

my guess after digging through my books (and it may be a very wild guess, but it's the closest thing i could find) is something to do with "readdir".

now i'm not sure how this would work though. i can get a listing of existing directories, but get kind of lost after that. can you help me here?

© Copyright 2002 C.G. Ward - All Rights Reserved
Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
1 posted 2002-11-17 10:43 PM


an additional question while we're in here: can you help me with the syntax used to include a file into your script? i recall seeing, somewhere that it can be done, but i seem to be having problems with it...?

require "$ENV{DOCUMENT_ROOT}/cgi-bin/test/toolbox.pl";

gives me the error:

Can't locate /big/dom/xcountlesshorizons/www/cgi-bin/test/toolbox.pl in @INC (@INC contains: /usr/local/lib/perl5/5.00503/i686-linux /usr/local/lib/perl5/5.00503 /usr/local/lib/perl5/site_perl/5.005/i686-linux /usr/local/lib/perl5/site_perl/5.005 .) at db1.pl line 3.

Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
2 posted 2002-11-17 11:17 PM


You "could" get the next available ID by reading the directory.

opendir(DIR, "$Path2Dir");
@files = grep { /^\d+$/ } readdir(DIR);
closedir DIR;
sort (@files);
reverse (@files);
$LastID = $files[0];
$NextID = $LastID + 1;
$NextID = sprintf ("%5", $ NextID);
$NextID =~tr/ /0/;

The regular expression used with grep makes sure you only get files that are pure numbers. There are other ways to do it, of course, but in any case you need to filter out the "." and ".." directories. The returned files are then sorted and reversed, putting the highest numbered file first in the array. Note that this sort only works because the last two lines of that code reformat the number as a five digit zero-filled string (like 00123). While there are ways to sort numbers, in a standard ASCII sort 10 and 100 both come before 2, and that obviously doesn't work well.

The problem with this procedure is that it is too slow and encompassed too many steps. When you are assigning ID numbers it is absolutely imperative that two users who hit the submit button within a few seconds of each aren't assigned the same ID. Were that to happen, the last one to be processed will overwrite the first, leaving no trail at all. One user is just completely lost.

Here's a different way, one that eliminates that possibility.

&GetTheLock;
Open (IDFILE, "<$Path/id.db");
$LastID = <IDFILE>;
CLOSE (IDFILE);
$NextID = $LastID + 1;
Open (IDFILE, ">$Path/id.db");
print IDFILE $NextID;
CLOSE (IDFILE);
&DropTheLock;

sub GetTheLock {
   my $endtime = time + 10;
   # if the idlock.file already exists we need to wait for it to be deleted
   while ((-e "$Path/idlock.file") && (time < $endtime)) {
      sleep(1);
   }
   open (LOCKFILE, ">$Path/$idlock.file");
}

sub DropTheLock {
   close (LOCKFILE);
   unlink ("$NonCGIPath/$lockname");
}

Reading and writing individual files (especially tiny ones holding just a single number) is typically much faster than reading and sorting what could potentially grow into a very large directory. Even without the locking routines, it would be difficult for two users to hit the submit button close enough together to get the same ID number, and with the lock routines, it should be impossible. The disadvantage of this procedure, of course, is that it depends on that tiny file being there - so you have to careful to build it, by hand if necessary, before the system goes live.

Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
3 posted 2002-11-17 11:35 PM


The require pragma will look in the specified path first and, if it can't find it, then look in all the paths in the special @INC environment variable. Either the file isn't where you think it is, or (and this is my best guess) your server is configured to block references above your own assigned area. For obvious reasons, they don't want you writing files in /big/dom/ and the block is preventing you from using that as an absolute reference. I suspect "your" absolute path begins at /xcountlesshorizons and the ENVironment variable set by Perl is wrong.

However, if your program is in the same directory as the file it wants to require, you don't need to include a path at all. If it's not in the same directory, you should be able to use a relative path. So, if the running program is in the same directory you just do a:

require "toolbox.pl";

If the running program is in cgi-bin you would do a :

require "test/toolbox.pl";

Unless there's a good reason to do otherwise, it's fairly standard practise to keep your include files in the same dir as the programs that need them.

Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
4 posted 2002-11-17 11:53 PM


on the last - i tried that initially, and again, just now.

with:

     require "toolbox.pl";

i end with the error:

     toolbox.pl did not return a true value at db3.pl line 3.

yet i KNOW it is there, i can see it there in the same directory. i must be missing something or doing something wrong.

for the first part - working on it right now... thanks Ron.

Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
5 posted 2002-11-18 12:00 PM


this part, i don't get:


   unlink ("$NonCGIPath/$lockname");


unlink makes me think of not referencing it anymore, but i'm not following on the rest...

Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
6 posted 2002-11-18 05:26 PM


An included or required file MUST return a value of True, which is why you're getting the error. Easy to fix, though. Load toolbox.pl, scroll to the end of the file, past the last function even, and insert:

1;

The 1 will be interpreted as True.

The unlink command just deletes the lock file, Chris. In the lock routine, we create a file (albeit an empty one), and we know as long as that file exists, we shouldn't try to open the ID file a second time. After we've finished our read and writes to the ID file, we call the unlock routine. It's only job is to close the lock file and delete it so we know the lock has been dropped.

Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
7 posted 2002-11-18 08:15 PM


oh cool, thank you, that makes sense. Why, out of curiosity, does it need to be in a non-cgi path?
Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
8 posted 2002-11-18 08:26 PM


It doesn't. In fact, when I cut & pasted the text from one of my programs, I changed that variable in the lock routine to avoid that very confusion. Just forgot to follow through in the unlock routine.


Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
9 posted 2002-11-18 08:33 PM


ah-ha! gotcha!

since we're on this subject now: is it fairly safe to assume that for any files that may be used by more than one person at a time, it's a good idea to use this lock routine? and would it be basically the same, with only the variables and pathing changing? i would think so, but i like to check because i do miss things sometimes.

again, thanks teach.

Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
10 posted 2002-11-19 06:55 AM


Yes, and it essentially means ALL files in most applications, because your program can theoretically be running in dozens or hundreds of processes at the same time.

That means making some changes to the Lock and Unlock routines, though. Obviously, you don't want users A and B to access the id.db file at the same time. But A should probably be able to access id.db even though B is currently updating his profile, and the way our subroutines are currently written, your whole  application can only have a single file open for updates. To be honest, that actually works on most system, just because computers are really fast and most sites don't have that many visitors working at the same time. But we can do better.

sub GetTheLock {

   my $lockfile = $_[0];

   my $endtime = time + 10;
   # if the file already exists we need to wait for it to be deleted
   while ((-e "$Path/$lockfile.lock") && (time < $endtime)) {
      sleep(1);
   }
   open (LOCKFILE, ">$Path/$lockfile.lock ");
}

sub DropTheLock {

   my $lockfile = $_[0];

   close (LOCKFILE);
   unlink ("$Path /$lockfile.lock ");
}

By passing in the file name, we can now lock multiple files. So before updating the id.db file, I would do a GetTheLock("id"), and before updating the profile file I might do a GetTheLock("00031") (or however you name the profile records).

The thing to remember about this locking scheme is that it's completely voluntary. Perl doesn't force your programs to check for a lock before updating a file, and if you write even a single routine that doesn't call both the lock and unlock routines the whole scheme becomes unreliable. The key is consistency.

Christopher
Moderator
Member Rara Avis
since 1999-08-02
Posts 8296
Purgatorial Incarceration
11 posted 2002-11-19 07:18 AM


Had to read it three times, scratching my head, lol, but i got it. That makes complete sense.

Now, in your opinion (because I value it), do you think that "consistency" would include files that are only being read? ie: when you're reading through your members.idx for an existing email address, would you bother locking it? Just curious (again... poor cats).

Ron
Administrator
Member Rara Avis
since 1999-05-19
Posts 8669
Michigan, US
12 posted 2002-11-19 09:39 AM


Nope. No need. Just the files that are being updated and then only when they are updated. It's almost a game with me to see just how FEW lines of code I can put between the Lock and Unlock.
Post A Reply Post New Topic ⇧ top of page ⇧ Go to Previous / Newer Topic Back to Topic List Go to Next / Older Topic
All times are ET (US). All dates are in Year-Month-Day format.
navwin » Tech Talk » Beyond the Basics » Reading Directory Listings

Passions in Poetry | pipTalk Home Page | Main Poetry Forums | 100 Best Poems

How to Join | Member's Area / Help | Private Library | Search | Contact Us | Login
Discussion | Tech Talk | Archives | Sanctuary