src/modules/misc.py
changeset 1035 0e243b7eb121
parent 1026 d4aa3ac69dc0
child 1038 2514d758e462
--- a/src/modules/misc.py	Thu Apr 09 23:22:23 2009 -0700
+++ b/src/modules/misc.py	Fri Apr 10 08:38:03 2009 -0700
@@ -40,6 +40,7 @@
 import sha
 import shutil
 import socket
+import struct
 import sys
 import time
 import urllib
@@ -431,9 +432,11 @@
 
                 return False, text
 
-def bytes_to_str(bytes):
+def bytes_to_str(bytes, format=None):
         """Returns a human-formatted string representing the number of bytes
-        in the largest unit possible."""
+        in the largest unit possible.  If provided, 'format' should be a string
+        which can be formatted with a dictionary containing a float 'num' and
+        string 'unit'."""
 
         units = [
             (_("B"), 2**10),
@@ -452,8 +455,12 @@
                         # unit of measure's range.
                         continue
                 else:
-                        return "%.2f %s" % (round(bytes / float(
-                            limit / 2**10), 2), uom)
+                        if not format:
+                                format = "%(num).2f %(unit)s"
+                        return format % {
+                            "num": round(bytes / float(limit / 2**10), 2),
+                            "unit": uom
+                        }
 
 def get_rel_path(request, uri):
         # Calculate the depth of the current request path relative to our base
@@ -558,6 +565,46 @@
 
         return fhash.hexdigest(), content.read()
 
+def __getvmusage():
+        """Return the amount of virtual memory in bytes currently in use."""
+
+        # This works only on Solaris, in 32-bit mode.  It may not work on older
+        # or newer versions than 5.11.  Ideally, we would use libproc, or check
+        # sbrk(0), but this is expedient.  In most cases (there's a small chance
+        # the file will decode, but incorrectly), failure will raise an
+        # exception, and we'll fail safe.
+        try:
+                # Read just the psinfo_t, not the tacked-on lwpsinfo_t
+                psinfo_arr = file("/proc/self/psinfo").read(232)
+                psinfo = struct.unpack("6i5I4LHH6L16s80siiIIc3x7i", psinfo_arr)
+                vsz = psinfo[11] * 1024
+        except Exception:
+                vsz = None
+
+        return vsz
+
+def out_of_memory():
+        """Return an out of memory message, for use in a MemoryError handler."""
+
+        vsz = bytes_to_str(__getvmusage(), format="%(num).0f%(unit)s")
+
+        if vsz is not None:
+                error = """\
+There is not enough memory to complete the requested operation.  At least
+%(vsz)s of virtual memory was in use by this command before it ran out of memory.
+You must add more memory (swap or physical) or allow the system to access more
+existing memory, or quit other programs that may be consuming memory, and try
+the operation again."""
+        else:
+                error = """\
+There is not enough memory to complete the requested operation.  You must
+add more memory (swap or physical) or allow the system to access more existing
+memory, or quit other programs that may be consuming memory, and try the
+operation again."""
+
+        return _(error) % locals()
+
+
 class CfgCacheError(Exception):
         """Thrown when there are errors with the cfg cache."""
         def __init__(self, args=None):