Saturday, September 11, 2010

block size

多处都存在block size, 概念同名但是意义不同, 相当迷惑
这哥们就是一个被迷惑的人: http://www.linuxforums.org/forum/misc/5654-linux-disk-block-size-help-please.html

上面的URL列出了如下几种block:
1. Hardware block size, "sector size"
2. Filesystem block size, "block size"
3. Kernel buffer cache block size, "block size"
4. Partition table block size, "cylinder size"

我对fdisk打印的blocks一栏很不解. 需要dig一下.
先来看看fdisk打印出来的block:

jessinio@jessinio-laptop:/ $ sudo fdisk -l
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1         100      803218+  83  Linux
/dev/sda2             101       30401   243392782+  8e  Linux LVM

上面的内容和下面的是一致的:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 512 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1         100      803218+  83  Linux
/dev/sda2             101       30401   243392782+  8e  Linux LVM

但是下面的就比较奇怪了:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 1024 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 15200 cylinders
Units = cylinders of 16065 * 1024 = 16450560 bytes
Disk identifier: 0x00038329

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1         100     1606437   83  Linux
/dev/sda2             101       30401   486785565   8e  Linux LVM

指定更大的硬件sector size反而block增加, 这是为什么呢?。下面是fdisk的相关代码:
sector_size变量的来源:
 759 static void
 760 get_sectorsize(int fd) {
 761 #if defined(BLKSSZGET)
 762     if (!user_set_sector_size && 
 763         linux_version_code() >= MAKE_VERSION(2,3,3)) {
 764         int arg;
 765         if (ioctl(fd, BLKSSZGET, &arg) == 0)
 766             sector_size = arg;
 767         if (sector_size != DEFAULT_SECTOR_SIZE)
 768             printf(_("Note: sector size is %d (not %d)\n"),
 769                    sector_size, DEFAULT_SECTOR_SIZE);
 770     }
 771 #else
 772     /* maybe the user specified it; and otherwise we still
 773        have the DEFAULT_SECTOR_SIZE default */
 774 #endif
 775 }
DEFAULT_SECTOR_SIZE 在fdisk.h中定义是
#define DEFAULT_SECTOR_SIZE     512

或者是用户指定的user_set_sector_sizesector_size = atoi(optarg);

打印时使用的代码是:
1731             unsigned int psects = get_nr_sects(p);
1732             unsigned int pblocks = psects;
1733             unsigned int podd = 0;
1734
1735             if (sector_size < 1024) {
1736                 pblocks /= (1024 / sector_size);
1737                 podd = psects % (1024 / sector_size);
1738             }
1739             if (sector_size > 1024)
1740                 pblocks *= (sector_size / 1024);
1741                         printf(
1742                 "%s  %c %11lu %11lu %11lu%c  %2x  %s\n",
1743             partname(disk_device, i+1, w+2),
1744 /* boot flag */     !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
1745             ? '*' : '?',
1746 /* start */     (unsigned long) cround(get_partition_start(pe)),
1747 /* end */       (unsigned long) cround(get_partition_start(pe) + psects
1748                 - (psects ? 1 : 0)),
1749 /* odd flag on end */   (unsigned long) pblocks, podd ? '+' : ' ',
1750 /* type id */       p->sys_ind,
1751 /* type name */     (type = partition_type(p->sys_ind)) ?
1752             type : _("Unknown"));
1753             check_consistency(p, i);

1. 当sector_size刚好等于1024时, 打印出的正好是sector的数目。也是partition的大小(同size概念)
2. 当sector_size不等于1024时,把sector数目和sector_size结合起来換算成大小(同size概念)

可见, fdisk打印的Blocks一栏其实是partition的大小。下面测试一下:

$ sudo mount /dev/sda1 /media/disk/
$ df /media/disk/
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1               790556     48176    702220   7% /media/disk
790556 是文件系统总大小。
上面的fdisk -b 1024 -l 命令得到的1606437是sector的数目。这样计算:

1606437 * 512 / 1024 =803218 是约等于790556 的。partition的大小是比file system大是因为file system需要存放一些信息.

1. 要想得到一个partition占有用多少个sector的话, 可以使用fdisk -b 1024这种方式得到
2. 不加-b参数的fdisk命令打印的Blocks一栏其实是表示partition的大小(以K为单位)
3. 还没有能力找出Kernel buffer cache block size, "block size" 这一条的实际代码

Wednesday, September 8, 2010

pkg-config

感觉centOS上的fuse版本太低, 还是从源代码安装。

简单编译后:
./configure --prefix=/usr/local/fuse

fuse-python-binding就无法安装。问题是fuse-python-binding的setup.py需要使用pkg-config取得编译参数。

 pkg-config --list-all  |grep fuse
无法找到pkg-config需要的*.pc metainfornation文件。

可以手工增加:

$ PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ pkg-config --list-all |grep fuse
fuse                        fuse - Filesystem in Userspace

所以, 下面的方法可以安装:
$ sudo PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ python setup.py install

[jessinio@niowork site-packages]$ /usr/local/python2.6/bin/python -c "import fuse"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "fuse.py", line 27, in <module>
    from fuseparts._fuse import main, FuseGetContext, FuseInvalidate
ImportError: libfuse.so.2: cannot open shared object file: No such file or directory


需要增加lib路径:
$ sudo sh -c "echo /usr/local/fuse/lib >> /etc/ld.so.conf.d/fuse.conf "
$ sudo ldconfig

Saturday, September 4, 2010

prefork服务器方式

WEB服务器一般都有两种模式处理动态服务:
1. prefork
2. thread

一种是使用多进程, 另一种是使用多线程.  它们的具体的实现方式自己其实并不清楚.
最近公司的python WEB服务使用较多的内存. 为了清楚其中的问题. 需要学习flup(django需要此库)代码. (  人家写的代码实在好看 )

很多软件都有prefork方式, 下面是prefork模型:

每个nginx子进程都分别调用accept得到用户发来的80端口请求.
之所以每个子进程都可以调用accept得到同一个socket的请求, 是因为fork出的子进程的file descriptor是指向同一个实体.

这样实现了多进程竟争得到socket请求.

每个子进程又可以使用epoll, 线程等方式并发处理众多来自80端口的请求. fast cgi server也是类似的方法.
nginx与fast cgi server之间使用socket通信, 使用fast cgi协议.


每个flup work某一时刻只服务一个页面请求. 完成请求后可以重新接受请求.

使用prefork模型的方式。 所以在PreforkServer类中。

父进程的主体是一个loop:

119         # Main loop.
120         while self._keepGoing:
121             # Maintain minimum number of children.
122             while len(self._children) < self._maxSpare:
123                 if not self._spawnChild(sock): break

可以看出, 父进程是永远期待子进程的数目为一个数值的。这个数值为maxSpare
粗粗看上去, 有些野。但是父进程是有回收子进程的策略的, 如下:

169             # See who and how many children are available.
170             availList = filter(lambda x: x[1]['avail'],
self._children.items())
171             avail = len(availList)

上面的代码可以知道, 父进程会一直收集可用的子进程。 所谓可用是没有在工作
的子进程, 可以从子进程的代码中看出, 如下:
370             # Notify parent we're no longer available.
371             self._notifyParent(parent, '\x00')
372
373             # Do the job.
374             self._jobClass(clientSock, addr, *self._jobArgs).run()

上面的代码是子进程在调用jobClass.run之前, 通知父进程自己是 no longer
available的。


父进程维护着“可用的子进程“数目是为了可以了解负载情况, 判断是否需要产生
更多的子进程, 如下:
172
173             if avail < self._minSpare:
174                 # Need to spawn more children.
175                 while avail < self._minSpare and \
176                       len(self._children) < self._maxChildren:
177                     if not self._spawnChild(sock): break
178                     avail += 1

上面的代码使用了两个数据: minSpare和maxChildren。

minSpare是表示最少“可用子进程“数
maxChildren是表示最大“子进程”数, 是空闲与工作的子进程总数

如果“可用子进程”数还剩一定数据,会被回收, 如下:

179             elif avail > self._maxSpare:
180                 # Too many spares, kill off the extras.
181                 pids = [x[0] for x in availList]
182                 pids.sort()
183                 pids = pids[self._maxSpare:]
184                 for pid in pids:
185                     d = self._children[pid]
186                     d['file'].close()
187                     d['file'] = None
188                     d['avail'] = False

从上面的代码可以看到, fast cgi在启动时的使用到的三个参数的作用应该是:
minspare: 最小“空闲进程数“
maxspare: 常规进程数,即fast cgi启动后, fastcgi进程数是大于等于此值
maxChildren: 最大进程数, 此值主要是用于防止内存被使用完的。

Friday, September 3, 2010

父类方法使用子类的方法与数据

对OO其实是不懂, 只是会一个class( 模式说白了不会. 接口是学了go语言才知道是什么. (-_-)! )

今天在看flup项目的代码时, 有一段发码看不懂. 其实是自己对OO的不懂:
 
  1 #coding:utf-8
  2
  3 class Parent(object):
  4     def __init__(self, name):
  5         self._name = "\t父类: %s" % name
  6     def whoami(self):
  7         print self._name
  8         print "在父类方面中调用子类的方法:"
  9         self._print()
 10         
 11         
 12 class Child(Parent):
 13     def __init__(self, name):
 14         self._nickname = "\t子类:%s" % name
 15         Parent.__init__(self, "大明")
 16         
 17     def _print(self):
 18         print self._nickname
 19         
 20     def run(self):
 21         # 下面的两种调用方法是一样的
 22         print "使用Parent.method(self)的方法调用父类方法"
 23         Parent.whoami(self)
 24         print "使用self.method()的方法调用父类方法"
 25         self.whoami()
 26         
 27         
 28         
 29 if __name__ == "__main__":
 30     c = Child("小明")
 31     c.run()

平时一般都是使用self.whoami(), 自为发父方法无法使用子类的东西. 但是如果使用Parent.whoami(self) 的方式, 就会明白自己的理解其实是错的.

基本问题是自己没有对书中的Parent.__init__(self, "大明") 一句理解到位

嗯.... 自己的水平太差了.