[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

managment of a full file partition



    Date: Tue, 7 Feb 89 10:43:14 N
    From: baechler%elma.epfl.ch@CUNYVM.CUNY.EDU

     Several weeks ago, I encountered the following problem:

     the partition of our server machine was full and we didn't know what
    room occupied our different directories. I looked at the documentation and
    I didn't find any useful tool. But the problem was really annnoying and
    slowed down our work. Finally I decided to write a such tool by myself.

I guess that many of us have written some version of this tool.  Mine is
included below.

To use it, invoke the Show Disk Usage command on the root directory of
the part of the hierarchy that you are interested in.  It prints output
like the following:

Show Disk Usage1 0SYS:CONCORDIA;

Total records Local records Pathname
  1014 (100%)    319 (31%)  CHUCK:>sys>r7-2>concordia>
   639 (63%)     635 (63%)    CHUCK:>sys>r7-2>concordia>doc>
     4 (0%)        2 (0%)       CHUCK:>sys>r7-2>concordia>doc>patch>
     2 (0%)                       CHUCK:>sys>r7-2>concordia>doc>patch>concordia-doc-9>
    29 (3%)       23 (2%)     CHUCK:>sys>r7-2>concordia>locking>
     6 (1%)        3 (0%)       CHUCK:>sys>r7-2>concordia>locking>patch>
     3 (0%)                       CHUCK:>sys>r7-2>concordia>locking>patch>lock-simple-19>
    22 (2%)        1 (0%)     CHUCK:>sys>r7-2>concordia>standin>
    21 (2%)        2 (0%)       CHUCK:>sys>r7-2>concordia>standin>patch>
    19 (2%)                       CHUCK:>sys>r7-2>concordia>standin>patch>standins-1>
     5 (0%)        2 (0%)     CHUCK:>sys>r7-2>concordia>patch>
     3 (0%)                     CHUCK:>sys>r7-2>concordia>patch>concordia-13>

The display is a depth-first traversal.  At each new level the pathname
is indented a bit more.  All of the subdirs of a given directory are
displayed in largest-first order.  The "Total records" line is the
number of records included in the entire subhierarchy, including the
directory itself.  The "Local records" shows the record count of the
files that reside in that directory (not including subdirectories).
This column is blank if the entry has no subdirs.  All percentages are
in terms of the total number of records in the root's subtree, since I
usually use this to look for big payoffs.

I use the command to keep snapshots of the disk usage.

Show Disk Usage Chuck:> :Output Destination file c:>disk-usage-880210.text

I can then compare the current listing with the previous one to see
where the free records have gone.

Another sometimes-useful command, Show Total Records, is included as
well.  Unlike Show Disk Usage, it takes an "accordion wildcard" pathname
so you can restrict the search to files that match some pattern.  One
interesting use is to compare:

Show Total Records host:>my-project-dir>**>*.lisp.*

with

Show Total Records host:>my-project-dir>**>*.lisp.newest

to see how much space is used by old versions of your files.


;;; -*- Mode: LISP; Package: USER; Base: 10; Syntax: Common-lisp -*-

(cp:define-command (com-show-disk-usage :command-table 'user)
    ((path 'pathname :default (send (send (send (si:pathname-history-first-pathname)
						:translated-pathname)
					  :directory-pathname-as-file)
				 :pathname-as-directory)))
   (disk-usage-sorted (send path :new-pathname :name :wild :type :wild :version :wild)))

(defun disk-usage-sorted (dir)
  (labels ((collect-data (dir)
	     (tv:alter-progress-note-text (format nil "Scanning ~A" dir))
	     (loop for (path . props) in (fs:directory-list dir :sorted)
		   when (getf props :directory)
		     collect (multiple-value-list
			       (collect-data (send path :pathname-as-directory)))
		       into subdir-info
		   when (getf props :length-in-blocks)
		     sum (getf props :length-in-blocks) into shallow-space
		   finally
		     (let ((deep-space 0))
		       (loop for (subdir-path deep shallow) in subdir-info
			     do
			 (incf deep-space (+ deep shallow)))
		       (return (values dir deep-space shallow-space subdir-info))))))
    (let ((data (multiple-value-list
		  (tv:noting-progress-alterable-note ("Scanning hierarchy")
		    (collect-data (send dir :translated-pathname)))))
	  total-space-used)
      (labels ((print-data (entry level)
			   (destructuring-bind (path deep shallow subdir-info)
			       entry
			     (formatting-row ()
			       (formatting-cell ()
				 (format t "~6D (~D%)"
					 (+ shallow deep)
					 (round (* (/ (+ shallow deep) total-space-used) 100))))
			       (formatting-cell ()
				 (if subdir-info
				     (format t "~6D (~D%)"
					     shallow
					     (round (* (/ shallow total-space-used) 100)))
				     (format t " ")))
			       (formatting-cell ()
				 (format t "~v@T~A"
					 level
					 (send (send path :directory-pathname-as-file)
					       :pathname-as-directory))))
			     (loop for sub in (sort (copy-list subdir-info)
						    #'> :key #'(lambda (e)
								 (+ (second e) (third e))))
				   do
			       (print-data sub (+ level 2))))))
	(destructuring-bind (nil deep shallow nil)
	    data
	  (setq total-space-used (+ deep shallow))
	  (fresh-line)
	  (terpri)
	  (formatting-table ()
	    (formatting-column-headings (t :underline-p t)
	      (formatting-cell ()
		"Total records")
	      (formatting-cell ()
		"Local records")
	      (formatting-cell ()
		"Pathname"))
	    (print-data data 0)))))))

(cp:define-command (com-show-total-records :command-table 'user)
    ((paths '((sequence pathname))))
   (loop for path in paths
	 for (f r b) =
	     (multiple-value-list 
	       (loop for (pn . props) in (fs:directory-list path)
		     count pn into files
		     when pn
		       sum (getf props :length-in-bytes 0) into bytes
		     when pn
		       sum (getf props :length-in-blocks 0) into records
		     finally (return (values files records bytes))))
	 sum f into files
	 sum r into records
	 sum b into bytes
	 finally (format t "~&~:D files, total records used = ~:D (~:D bytes)"
			 files records bytes)))