steve@nuchat.UUCP (Steve Nuchia) (03/15/88)
Here is a shar of the local code I've put together to make news run faster on my poor little 286. It will take some customization to get it going on your system but if you are having trouble with disk space fluctuation and/or running out of cycles before you run out of news it will be worth it. Oh, something I forgot to mention in the README: You need to build a 13-bit version of compress. This will run a whole lot faster and use a lot less memory than the 16-bit version. The penalty on uucp is only about 15% and you save a whole lot of cpu and Kcore minutes. Use the 13 bit version for your local feeds (and convince them to reciprocate) and keep the 16 bit compress around for long distance feeds and long-term storage compression. ------ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README crontab ifuncs.patch news.rc newsd.c recv.c # rnews.sh sendsome # Wrapped by usenet@nuchat on Mon Mar 14 21:42:16 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(2555 characters\) sed "s/^X//" >README <<'END_OF_README' XThese changes are motivated by the observation that Xthe news receiving process is painfully slow on non-dbm Xsites. Given that dbm was introduced specifically to speed Xsuch things up that should be no surprise. Nevertheless XI wanted to do what I could to improve the non-dbm case. X XHere's the code. X XFirst, there is a minor hack in ifuncs.c that inproves the Xhistory scan speed noticably. The old loop was reading in Xa line, mapping the whole thing to lower case, then calling Xthe STRCMP macro on it. Since the first character is '<' Xthe optimization on the macro, comparing the first character Xbefore investing in a function call, was wasted. And since Xthe second character differs in an overwhelming proportion Xof the cases the lower case mapping scan was a waste. X XThen there's the revised unbatch pipeline. The newsd Xdaemon is started from news.rc at boot time and is Xresponsible for serializing unbatching and expiring Xactivities and for monitoring the space on the disks Xinvolved in news handling. The rules embodied in it Xare the result of extensive tuning in my environment. XYou will have to tune it for your to get good stability. X XSubordinate to newsd is a new batch cracker, recv. This Xone serializes the decompress with respect to the rnews Xruns, which is a win on systems with limited memory. The Xbig win in recv is that it sorts the batch by history Xhash value so that the ten history database files are Xread at most once each. Without this optimization the Xblock cache is completely ineffective, and in my system Xadding the optimization cut the disk accesses per news Xarticle received in half. X XThe rnews.sh script is what I put on uuxqt's path, ie in X/usr/bin. Real rnews, the link to inews, is in /usr/lbin Xon my system. This has the side benefit of eliminating Xthe uuxqt lock breakage problem many small systems have Xbeen experiencing. X XThe other thing newsd does is dynamically adjust the Xexpire horizon. This is a big win, as it allows you Xto run arbitrarily close to max all the time safely. X XAlso included is my batch master script, which I run from Xcron every ten minutes. What the heck, I'll throw in Xmy crontab for completeness. Anyway, my batch sender Xhelps keep me out of trouble by not spooling when there Xisn't enough room or there is already too much spooled Xfor a given neighbor. These features are in the latest Xsendbatch.sh if you can figure them out, but I like Xmine better. X XAll this code is original and is hereby placed in Xthe public domain. X X Steve Nuchia X 14 March 1988 X (713) 334 6720 steve@nuchat END_OF_README if test 2555 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f crontab -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"crontab\" else echo shar: Extracting \"crontab\" \(158 characters\) sed "s/^X//" >crontab <<'END_OF_crontab' X8,18,28,38,48,58 * * * * /usr/lib/news/sendsome 2>&1 | (head; cat > /dev/null) X5 4 15 * * TZ=CST6CDT; /usr/lib/news/arbitron X35 1 * * * /usr/lib/news/trimlib END_OF_crontab if test 158 -ne `wc -c <crontab`; then echo shar: \"crontab\" unpacked with wrong size! fi # end of overwriting check fi if test -f ifuncs.patch -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"ifuncs.patch\" else echo shar: Extracting \"ifuncs.patch\" \(865 characters\) sed "s/^X//" >ifuncs.patch <<'END_OF_ifuncs.patch' X# Sorry, I don't have a context diff program yet. X# X# The snippet below should make it obvious what to X# do, only the SWN lines and the else case are X# new, and there are no other changes. X# X# steve X# X hfp = xfopen(histfile(lcident), "r"); X while (fgets(bfr, BUFLEN, hfp) != NULL) { X#ifdef SWN_SLOW X p = index(bfr, '\t'); X if (p == NULL) X p = index(bfr, '\n'); X if (p != NULL) /* can happen if nulls in file */ X *p = 0; X lcase(bfr); X X if (STRCMP(bfr, lcident) == 0) X#else SWN_SLOW X for ( p = bfr, q = lcident; *q; q++, p++ ) X { X if ( *p == '\t' || *p == '\n' ) break; X if ( isupper(*p) ) *p = tolower(*p); X if ( *p != *q ) break; X } X if ( ! *q && ( ! *p || *p == '\t' || *p == '\n' ) ) X#endif SWN_SLOW X { X (void) fclose(hfp); X idunlock(); X#ifdef DEBUG X fprintf(stderr,"history returns true\n"); X#endif /* DEBUG */ X return TRUE; END_OF_ifuncs.patch if test 865 -ne `wc -c <ifuncs.patch`; then echo shar: \"ifuncs.patch\" unpacked with wrong size! fi # end of overwriting check fi if test -f news.rc -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"news.rc\" else echo shar: Extracting \"news.rc\" \(465 characters\) sed "s/^X//" >news.rc <<'END_OF_news.rc' X: Xcd /usr/spool/news/incoming X(echo news\\c > /dev/console) Xfor x in `ls | grep '^in'` Xdo X for l in a b c d e f g h i j k l m n o p X do X if [ ! -f $l$x ] X then X mv $x $l$x X break X fi X done Xdone X Xcd /usr/lib/news Xrm -f send.lock Xmv newsd.log onewsd.log XPATH=/usr/lib/news:/usr/lbin:/usr/bin:/bin:. ; export path X(echo " daemon\\c" > /dev/console) Xsu - usenet -c "cd /usr/lib/news; exec ./newsd &" < /dev/null > newsd.log 2>&1 X(echo " started" > /dev/console) END_OF_news.rc if test 465 -ne `wc -c <news.rc`; then echo shar: \"news.rc\" unpacked with wrong size! fi # end of overwriting check fi if test -f newsd.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"newsd.c\" else echo shar: Extracting \"newsd.c\" \(2870 characters\) sed "s/^X//" >newsd.c <<'END_OF_newsd.c' X/* X * newsd.c - daemon for unbundling news and doing other X * essential stuff, like running expire. Obviates certain X * cron processing and allows the slow components of news X * to run niced without playing uucp games. X * X * Steve Nuchia X * 27 Sept 1987 X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <ustat.h> X#include <sys/dir.h> X#include <stdio.h> X X#define INCOMING "/usr/spool/news/incoming" X#define OOPS "/usr/spool/news/oops" X#define UNPACK "/usr/lib/news/recv" X#define IHAVE "/files/news/.ihave" X#define OUTGOING "/usr/spool/batch" X#define NEWSDIR "/files/news" X#define SPOOLDIR "/usr/spool" X Xmain ( argc, argv ) X int argc; X char *argv[]; X{ X int incoming; X struct direct art; X char aname[DIRSIZ+1], abest[DIRSIZ+1], fullname[80], best[80], command[160]; X long btime, xtime; X int i; X struct stat sbuf; X struct ustat usbuf; X int scount = 25, days = 15; X X if ( argc > 1 ) X days = atoi ( argv[1] ); X time(&xtime); X nice ( 20 ); X if ( (incoming = open ( INCOMING, 0 )) < 0 ) perror ( INCOMING ); X X while ( 1 ) X { X sleep ( 60 ); X /* see how the space situation looks */ X stat ( NEWSDIR, &sbuf ); X ustat ( sbuf.st_dev, &usbuf ); X if ( usbuf.f_tfree > 1000 && usbuf.f_tinode > 500 ) X { X scount = 0; X /* look around in INCOMING */ X lseek ( incoming, 2L * sizeof(struct direct), 0 ); X best[0] = 0; X X while ( read ( incoming, &art, sizeof(struct direct) ) > 0 ) X { X if ( ! art.d_ino ) continue; X for ( i = 0; i < DIRSIZ; i++ ) aname[i] = art.d_name[i]; X aname[i] = 0; X sprintf ( fullname, "%s/%s", INCOMING, aname ); X stat ( fullname, &sbuf ); X if ( ! best[0] || btime > sbuf.st_mtime ) X { X btime = sbuf.st_mtime; X strcpy ( best, fullname ); X strcpy ( abest, aname ); X } X } X /* if there is anything, take care of oldest */ X if ( best[0] ) X { X sprintf ( command, "%s %s", UNPACK, best ); X if ( system ( command ) ) X { X sprintf ( command, "%s/%s", OOPS, abest ); X link ( best, command ); X } X unlink ( best ); X continue; X } X } X else X { X printf ( "space problem in NEWSDIR %d\n", ++scount ); X fflush ( stdout ); X sleep ( 120 ); X } X /* otherwise we are free to do housekeeping */ X stat ( SPOOLDIR, &sbuf ); X ustat ( sbuf.st_dev, &usbuf ); X if ( usbuf.f_tfree > 5000 && usbuf.f_tinode > 500 ) X { X if ( scount > 30 ) /* 30 times around with no space */ X { X time(&btime); X scount = 20; X days = days - 1 + (btime - xtime) / (23 * 3600L); X xtime = btime; X sprintf ( command, "echo %d > expire.days", days ); X system ( command ); X sprintf ( command, "expire -e%d -v -a >> expire.log 2>&1", X days ); X printf ( "%s\n", command ); X fflush ( stdout ); X system ( command ); X } X } X else X { X if ( scount > 25 ) scount = 25; X printf ( "space problem in SPOOLDIR\n" ); X fflush ( stdout ); X sleep ( 180 ); X } X } X} END_OF_newsd.c if test 2870 -ne `wc -c <newsd.c`; then echo shar: \"newsd.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f recv.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"recv.c\" else echo shar: Extracting \"recv.c\" \(3392 characters\) sed "s/^X//" >recv.c <<'END_OF_recv.c' X#include <sys/types.h> X#include <sys/stat.h> X Xchar buf[256]; X Xmain ( argc, argv ) X int argc; X char *argv[]; X{ X int fd, pfd[2], size; X X close ( 0 ); X fd = open ( argv[1], 0 ); X if ( fd != 0 ) X { X perror ( argv[1] ); X exit(1); X } X read ( fd, buf, sizeof(buf) ); X if ( ! strncmp ( buf, "#! cunbatch\n", 12 ) X && buf[12] == 0037 && buf[13] == (char) 0235 ) X { X size = buf[14] & 0x1f; X lseek ( fd, 12L, 0 ); X pipe ( pfd ); X if ( ! fork() ) X { X close ( 1 ); X dup ( pfd[1] ); X close ( pfd[0] ); X close ( pfd[1] ); X if ( size <= 13 ) X execl ( "/usr/lbin/comp12", "comp12", "-d", (char *) 0 ); X else X execl ( "/usr/lbin/comp16", "compress", "-d", (char *) 0 ); X perror ( "compress" ); X exit(1); X } X close ( fd ); X dup ( pfd[0] ); X close ( pfd[0] ); X close ( pfd[1] ); X exit ( unbatch() ); X } X /* never mind... */ X lseek ( fd, 0L, 0 ); X exit(unbatch()); X} X Xchar bbuf[1024]; X Xextern long atol(); X Xunbatch() X{ X int new = 1; X int len = 0, st, i; X int ch; X long alen; X char *p, *q; X int ofd[10]; X char fname[128]; X int rnews, xstat, rv = 0; X int pfd[2]; X X for ( ch = 0; ch < 10; ch++ ) X { X sprintf ( fname, "/usr/spool/news/decomp/recv.%d", ch ); X ofd[ch] = creat ( fname, 0600 ); X } X while ( len += bbfill ( bbuf + len, 1024 - len ) ) X { X if ( strncmp ( bbuf, "#! rnews ", 9 ) ) X { X if ( new ) X punt ( bbuf, len ); X printf ( "garbled news\n" ); X exit ( 1 ); X } X new = 0; X alen = atol ( bbuf + 9 ); X for ( st = 0; st < len && bbuf[st] != '\n'; st++ ); X st++; X ch = 0; X for ( p = bbuf + st; !ch && p < bbuf + len; p++ ) X { X if ( strncmp ( p, "Message-ID: ", 12 ) ) X while ( p < bbuf + len && *p != '\n' ) p++; X else X while ( p < bbuf + len && *p != '\n' && *p != '\@' ) ch = *p++; X } X if ( ch < '1' || ch > '9' ) ch = '0'; X ch -= '0'; X while ( alen && len ) X { X i = len - st; X if ( i > alen ) i = alen; X write ( ofd[ch], bbuf, st + i ); X alen -= i; X bcopy ( bbuf + st + i, bbuf, len = len - st - i ); X st = 0; X len += bbfill ( bbuf + len, 1024 - len ); X } X } X for ( ch = 0; ch < 10; ch++ ) close ( ofd[ch] ); X for ( ch = 0; ch < 10; ch++ ) X { X sprintf ( fname, "/usr/spool/news/decomp/recv.%d", ch ); X if ( ! (rnews = fork()) ) X { X struct stat sbuf; X X stat ( fname, &sbuf ); X if ( !sbuf.st_size ) exit ( 0 ); X close ( 0 ); X open ( fname, 0 ); X execl ( "/usr/lbin/rnews", "rnews", (char *) 0 ); X perror ( "rnews" ); X exit ( 1 ); X } X while ( wait ( &xstat ) != rnews ); X unlink ( fname ); X rv |= xstat | (xstat >> 8); X } X return ( rv ); X} X Xbcopy ( f, t, l ) X char *f, *t; X{ X while ( l-- ) *t++ = *f++; X} X Xbbfill ( p, s ) X char *p; X int s; X{ X int len = 0, rv; X X while ( len < s ) X { X if ( (rv = read ( 0, p + len, s - len )) > 0 ) X len += rv; X else X break; X } X return ( len ); X} X Xpunt ( buf, len ) X char buf[]; X int len; X{ X int pfd[2], rnews, xstat; X X pipe ( pfd ); X if ( ! (rnews = fork()) ) X { X close ( 0 ); X dup ( pfd[0] ); X close ( pfd[0] ); X close ( pfd[1] ); X execl ( "/usr/lbin/rnews", "rnews", (char *) 0 ); X perror ( "rnews" ); X exit ( 3 ); X } X close ( pfd[0] ); X write ( pfd[1], buf, len ); X while ( (len = read ( 0, buf, 1024 )) > 0 ) X write ( pfd[1], buf, len ); X close ( pfd[1] ); X while ( wait ( &xstat ) != rnews ); X exit ( xstat | (xstat >> 8) ); X} END_OF_recv.c if test 3392 -ne `wc -c <recv.c`; then echo shar: \"recv.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f rnews.sh -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"rnews.sh\" else echo shar: Extracting \"rnews.sh\" \(109 characters\) sed "s/^X//" >rnews.sh <<'END_OF_rnews.sh' Xumask 0222 Xcat - >> /usr/spool/news/incoming/in.$$ Xls -l /usr/spool/news/incoming/in.$$ >> /usr/lib/news/log END_OF_rnews.sh if test 109 -ne `wc -c <rnews.sh`; then echo shar: \"rnews.sh\" unpacked with wrong size! fi chmod +x rnews.sh # end of overwriting check fi if test -f sendsome -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sendsome\" else echo shar: Extracting \"sendsome\" \(1589 characters\) sed "s/^X//" >sendsome <<'END_OF_sendsome' X: X Xeval `df | grep /usr | awk '{ print "BLKS=" $3 "; INODS=" $5 }'` X Xif test -z "$BLKS" -o -z "$INODS" -o "$BLKS" -lt 7000 -o "$INODS" -lt 100 Xthen X exit Xfi X Xif [ -f /usr/lib/news/send.lock ] Xthen X if kill -0 `cat /usr/lib/news/send.lock` 2> /dev/null X then X exit X else X rm /usr/lib/news/send.lock X fi Xfi X Xecho $$ > /usr/lib/news/send.lock X Xeval `uustat -q | tail +1 | awk '{print $1 "=" $3}'` X Xif test -z "$tness1" -o "$tness1" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 tness1 Xfi X Xif test -z "$sugar" -o "$sugar" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 sugar Xfi X Xif test -z "$uunet" -o "$uunet" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -c uunet Xfi X Xif test -z "$meow" -o "$meow" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 -b12 meow Xfi X Xif test -z "$uhnix1" -o "$uhnix1" -lt 6 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 uhnix1 Xfi X Xif test -z "$splut" -o "$splut" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 splut Xfi X Xif test -z "$flatli" -o "$flatli" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 flatline Xfi X Xif test -z "$amdahl" -o "$amdahl" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -c amdahl Xfi X Xif test -z "$siswat" -o "$siswat" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 siswat Xfi X Xif test -z "$killer" -o "$killer" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 killer Xfi X Xif test -z "$shell" -o "$shell" -lt 4 Xthen X nice -20 /usr/lib/news/sendbatch -cp/usr/lbin/comp12 shell Xfi X Xrm /usr/lib/news/send.lock END_OF_sendsome if test 1589 -ne `wc -c <sendsome`; then echo shar: \"sendsome\" unpacked with wrong size! fi chmod +x sendsome # end of overwriting check fi echo shar: End of shell archive. exit 0 -- Steve Nuchia | [...] but the machine would probably be allowed no mercy. uunet!nuchat!steve | In other words then, if a machine is expected to be (713) 334 6720 | infallible, it cannot be intelligent. - Alan Turing, 1947