存档
在使用tar命令解压文件的时候,两次都出现了checksum error的错误,只是错误信息稍微有点差别。
情况1:
最近配置AIX下的Java环境,使用tar -xvf时总出现checksum error的信息。
# tar -xvf Java5_64.sdk.tar
x Java5_64.sdk, 74738688 bytes, 145974 media blocks.
tar: 0511-169 A directory checksum error on media; -265812960 not equal to 67621
最后发现原因,是因为我使用ftp下载时没有设置为二进制方式传输数据,ftp会默认使用Ascii的方式来传输,这样会破环文件。
解决方法: 登录ftp之后,输入bin,然后再使用get文件就可以了。
情况2:
用tar命令解压一个非tape archive文件时(格式为tgz),也报类似的错误!
-bash-3.2$ tar -xvf ase1503_aix64_2.tgz
tar: 0511-169 A directory checksum error on media; 0 not equal to 67634.
解决方法:先将tgz压缩文件转化成tar格式的,
$gunzip -S tgz ase1503_aix64_2.tgz
然后再用tar命令解压生成的ase1503_aix64_2.tar文件就可以了。
$tar -xvf ase1503_aix64_2.tar
————————————————————————————————————
——— 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
——— 转载务必注明原始出处 : http://www.dbainfo.net
——— 关键字:解压 tar 错误 aix gunzip
————————————————————————————————————
关于SQL2005安装失败的一种可行性解决办法
{英文原意如下
When you install Microsoft SQL Server 2005, you receive the following error message:
There was an unexpected failure during the setup wizard. You may review the setup logs and/or click the help button for more information.}
2、当我检查C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Summary.txt
Microsoft SQL Server 2005 9.00.1399.06
==============================
OS Version : Microsoft Windows Server 2003 family, Enterprise Edition Service Pack 2 (Build 3790)
Time : Wed Oct 10 08:34:17 2007
CSZ : 执行安装向导期间出错。有关详细信息,您可以查看安装日志和/或单击“帮助”按钮。
SQL Server 安装程序失败。有关详细信息,请查看 %ProgramFiles%\Microsoft SQL Server\90\Setup Bootstrap\LOG\Summary.txt 中的安装日志文件。
Time : Wed Oct 10 08:42:32 2007
List of log files:
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_Core(Local).log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_Datastore.xml
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework 2.0.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_Core.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Summary.txt
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework 2.0 LangPack.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Upgrade Advisor.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Upgrade Advisor LangPack.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Windows Installer.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Windows Installer LangPack.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_Support.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_SCC.log
C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_WI.log
3、当我检查到日志文件SQLSetup0001_CSZ_Core.log,发现在日志文件末尾有如下的错误提示:
{英文原意如下:
When you examine the SQLSetupNumber_ServerName_Core(local).log file at this point, you notice the following error message at the end of the log file: }
Running: InstallToolsAction.10 at: 2007/9/10 8:35:36
Error: Action "InstallToolsAction.10" threw an exception during execution. Error information reported during run:
Target collection includes the local machine.
Fatal Exception caught while installing package: "10"
Error Code: 0x80070002 (2)
Windows Error Text: 系统找不到指定的文件。
Source File Name: sqlchaining\sqlprereqpackagemutator.cpp
Compiler Timestamp: Tue Aug 9 01:14:20 2005
Function Name: sqls::SqlPreReqPackageMutator::modifyRequest
Source Line Number: 196
---- Context -----------------------------------------------
sqls::InstallPackageAction::perform
WinException caught while installing package. : 1603
Error Code: 0x80070643 (1603)
Windows Error Text: 安装时发生严重错误
Source File Name: packageengine\installpackageaction.cpp
Compiler Timestamp: Fri Jul 1 01:28:25 2005
Function Name: sqls::InstallPackageAction::perform
Source Line Number: 167
---- Context -----------------------------------------------
sqls::InstallPackageAction::perform
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework 2.0.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework 2.0 LangPack.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Upgrade Advisor.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Upgrade Advisor LangPack.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Windows Installer.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Error: Failed to add file :"C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup0001_CSZ_.NET Framework Windows Installer LangPack.log" to cab file : "C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\SqlSetup0001.cab" Error Code : 2
Running: UploadDrWatsonLogAction at: 2007/9/10 8:42:36
Message pump returning: 1603
4、问题解决
在d:盘根目录下建立sqlserver2005Setup目录,再在d:\sqlserver2005Setup\下创建2个目录
\Servers
\Tools
如 果是2个cd的安装程序,将cd1上的所有文件拷贝到Servers目录下,将cd2目录下的所有文件拷贝到Tools下;如果是一个dvd的安装程序, 则分别把dvd上的Servers和Tools目录下的所有文件分别拷贝到d:\sqlserver2005Setup\Servers和d: \sqlserver2005Setup\Tools
再进行安装应该就没有问题。
还有需要注意的问题
安装到上述错误的时候,SQL Server2005很多文件已经安装到硬盘上了,所有你重新安装的时候,可能会遇到
1、提示磁盘空间不够
目标磁盘中的空间不足,无法执行当前的 SQL Server 安装。若要继续,请释放磁盘空间以安装所选功能、为此次安装选择较少的功能或将所选功能安装到另一个驱动器中。
2、安装仍然失败
所以建议你重新安装之前,到添加删除程序里把SQL Server2005卸载掉!
上述问题是8月份我在一个客户那里搞了一个晚上都没有搞定,最后第二天早上在宾馆里上网到微软的网站上找到了答案,真是让人哭笑不得。
微软网站上标题为:
Error message when you install SQL Server 2005: "There was an unexpected failure during the setup wizard"
Article ID : 916760
Last Review : May 9, 2006
Revision : 2.0
Bug #: 408784 (SQLBUDT)
------------------------------------------------------------------------
性能计数器问题,主要是卸载SQL2005,再重新安装的错误,这方面的文章在网上很多,网友可搜索一下。
关于sql.cab找不到网上这样的疑问同样很多,但是没有明确的解答。这里说说我是怎么解决的。
应该说这是MSDN SQL2005安装程序的一个bug(不是十分确定),在SQL2005安装目录有两个子目录,一个是Servers目录, 一个是Tools目录,当初我只把Servers拷贝我硬盘上了,所以安装时如果选择了工作站组件、联机丛书和开发工具选项,安装到最后,就会提示你 sql.cab找不到(或其它安装不成功的提示信息),其实安装sql时先不要选该项,这样就可以安装成功,最后安装Tools的setup程序,它就是 仅安装该选项的安装包。
-------------------------------------------------------------
假如,以上这种办法还是出现SQL.CAB找不到类似的错误,那么你可以在上面那个办法的基础上,打开TOOLS文件夹(有的可能是CD2文件夹),找到TOOLS\Setup\SqlRun_Tools.msi并,运行,然后按照正常的安装流程来,这样应该可以解决了
题外话:我熬了好几个夜,把SQL2005装了删,删了装,终于装上了,真是辛苦啊~~。以上是我的安装解决办法的总结,有的是网站感觉比较有用的转载,有的是自己实际经历的过程的记录~~!
转自:http://www.nmju.net/article.asp?id=101
本帖子转自:echoaix 嘟嘟之家 http://blog.chinaunix.net/u/10212/showart.php?id=88834
向echoaix这位sybase 高手表示感谢。
转下面内容的原因是作个记录方便以后来查看如何在unix下修改文件内容。在windows下以十六进制形式修改文件内的数据很简单,可以用 UltraEdit这个强大的工具。我编出来了工具能够实现从sybase数据设备文件中提取数据和翻译解析sybase日志设备文件内容,这个过程中 UE提供了莫大的帮助。我编写的工具跟UE没有关系。但是,有时候对sybase设备文件做一个小小的修改的时候,我喜欢用UE。
但是,在unix环境下的sybase设备文件该如何修改呢?总不能每次都ftp下载下来,用windows下的Ultraedit改好了后再上传到服务器吧?
这样做太麻烦。
幸运的是,早有高手提供了解决的方法!厉害!
下面的代码我没有完全看明白,主要是没unix写过shell的原因。
大概意思是:向sh脚本传递3个参数,用指定数据替换指定文件中的相应偏移的相同字节的数据。
用od定位出被修改的偏移位置。然后用echo向dd传入数据,dd会处理这个文件。
至于如何将4个字节的数据转化到数组里的那段代码,我没有看懂!
-----------------------------------------------------------------------------
环境 :
iBM aix 4.3和sybase11.9 只有这环境
master设备/dev/rlvsybmaster1
前面还是一样看page内容:
dbcc traceon(3604)
go
dbcc tablealloc(sysdatabases) 或 select first from sysindexes where id = object_id("sysdatabases" and indid=1\\找到数据页(pageno)
go
dbcc page(master,pageno,1,0) \\从硬盘上拿这页内容详细内容
go
master的如下:
Offset 266 -
3256210a: 02000001 00010000 80000001 000008a1 ................
3256211a: 00000000 00000000 00009179 00fe9caa ...........y....
3256212a: 0005adda 00120034 6d617374 65728000 .......4master..
3256213a: 03302e28 .0.(.
用od命令定位(od命令真好)
#od -H /dev/lvsybmaster1 |grep '02000001 00010000 80000001 000008a1'
报找不到,郁闷,仔细看看dbcc page用法1(print page header, data rows and row offset table), 2 (print page header and hex dump of data page) 。改用dbcc page(master,pageno,2,0)
结果如下:不只这些,择了master的
32562110: 00008000 00010000 08a10000 00000000 ................
32562120: 00000000 917900fe 9caa0005 adda0012 .....y..........
32562130: 00346d61 73746572 80000330 2e280201 .4master...0.(..
32562140: 00030001 00000000 00010000 01e00000 ................
32562150: 00000000 00000000 917900fd acd60013 .........y......
32562160: 9866001e 00336d6f 64656c80 00032f2d .f...3model.../-
原来是顺序不同,怪不得grep找不到,再来:
#od -H /dev/lvsybmaster1 |grep '00008000 00010000 08a10000 00000000' 结果
2024420 00008000 00010000 08a10000 00000000 找到,注意这的偏移量是8进制的
找到如何改呢?知道应该用dd,叨咕半天,不行,上网求助 ,在liveunix看到“炸鸡”高人的帖子,给了一个sh如下
cat chvgid.sh
#!/usr/bin/ksh
vgid=$1
disk=$2
set -A a `echo $vgid|\
awk '{
for (f=1; f <= length($0); f=f+2) {
print "ibase=16\nobase=8\n"toupper(substr($0,f,2))
}
}'|bc 2>/dev/null`
/usr/bin/echo "\0"${a[0]}"\0"${a[1]}"\0"${a[2]}"\0"${a[3]}"\c"|dd bs=1 seek=3600 of=/dev/$disk
原来他是要直接改VGID的信息,看来能改的东西真不少。
到现在这个sh我还是看不很明白,但是用没问题,自己改了改如下
#cat chfile.sh
#!/usr/bin/ksh
dstatus=$1
filename=$2
offset=$3
set -A a `echo $dstatus|\
awk '{
for (f=1; f <= length($0); f=f+2) {
print "ibase=16\nobase=8\n"toupper(substr($0,f,2))
}
}'|bc 2>/dev/null`
/usr/bin/echo "\0"${a[0]}"\0"${a[1]}"\0"${a[2]}"\0"${a[3]}"\c"|dd bs=1 seek=$offset of=$filename conv=notrunc
加了$3偏移量,还有注意加conv=notrunc,要不你在修改点后的数据可能都没了。这的偏移量可是10进制的
od -Ad -H /dev/lvsybmaster1 |grep '00008000 00010000 08a10000 00000000' 找10进制偏移
0534800 00008000 00010000 08a10000 00000000
停sybase
改master设备
#chfile.sh 00000000 /dev/lvsybmaster1 534800
4+0 records in.
4+0 records out.
就是要把00008000 改为00000000
重启sybase ok
默认情况下.Solaris10安装完成后.启动是cde界面.但有时用xmanager登录时始终无法建立连接. 如果确认不是防火墙等方面的原因.可以用如下方法解决
1. 关闭默认的cde服务
svcadm disable cde-login
用ps-ef|grep dtlogin 应该看不到dtlogin进程了
2. 进入/etc/X11/gdm
编辑gdm.conf文件(也有可能是这两个文件/usr/share/gdm/defaults.conf 和/etc/X11/gdm/custom.conf) 编辑如下2个地方
找到[xdmcp]字段.
将Enable=flase改为true
将Port=177前的注释取消
然后保存退出.
3.ps-ef|grep gdm 确认目前没有gdm进程.如有杀之
4. 启动gdm服务
# svcs -a|grep gdm
disabled Aug_07 svc:/application/gdm2-login:default
# svcadm enable svc:/application/gdm2-login:default
然后在xmanager里建立新连接. 这样就可以登录了. 在登录界面的左上角选择cde.熟悉的cde界面就又回来了.
转载2 from: 彬彬有理 http://blog.chinaunix.net/u2/77786/showart_1161371.html -------------------------------------------------------------------------------------------------------------------------------------
root 101252 100995 0 15:09:01 ? 0:00 /usr/dt/bin/dtlogin -daemon -udpPort 0
root 101420 101419 0 15:13:47 pts/3 0:00 grep dtlogin
这里系统缺省监听udp port 0,就无法监听到177端口上的XDMCP请求
# /usr/dt/bin/dtlogin -daemon & 换daemon启动方式或者显式指定dtlogin -udpPort 177
svc:> select application/graphical-login/cde-login
大端(Big Endian)与小端(Little Endian)简介
///////////////////////////////////////////////////////
1. 你从哪里来?
端模式(Endian)的这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。采用大端方式 进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。下文举例说明在计算机中大小端模式的区别。
//////////////////////////////////////////////////////
2. 读书百遍其义自见
小端口诀: 高高低低 -> 高字节在高地址, 低字节在低地址
大端口诀: 高低低高 -> 高字节在低地址, 低字节在高地址
long test = 0x313233334;
小端机器:
低地址 --> 高地址
00000010: 34 33 32 31 -> 4321
大端机器:
低地址 --> 高地址
00000010: 31 32 33 34 -> 4321
test变量存储的是的0x10这个地址,
那编译器怎么知道是读四个字节呢? -> 根据变量test的类型long可知这个变量占据4个字节.
那编译器怎么读出这个变量test所代表的值呢? -> 这就根据是little endian还是big endian来读取
所以, 小端, 其值为0x31323334; 大端, 其值为0x34333231
htonl(test) 的情况: ->其值为: 0x34333231
小端机器:
00000010: 31 32 33 34 -> 1234
大端机器:
00000010: 34 33 32 31 -> 4321
/////////////////////////////////////////////////////////////////////////////////////
3. 拿来主义
Byte Endian是指字节在内存中的组织,所以也称它为Byte Ordering,或Byte Order。
对于数据中跨越多个字节的对象, 我们必须为它建立这样的约定:
(1) 它的地址是多少?
(2) 它的字节在内存中是如何组织的?
针对第一个问题,有这样的解释:
对于跨越多个字节的对象,一般它所占的字节都是连续的,它的地址等于它所占字节最低地址。(链表可能是个例外, 但链表的地址可看作链表头的地址)。
比如: int x, 它的地址为0x100。 那么它占据了内存中的Ox100, 0x101, 0x102, 0x103这四个字节(32位系统,所以int占用4个字节)。
上面只是内存字节组织的一种情况: 多字节对象在内存中的组织有一般有两种约定。 考虑一个W位的整数。
它的各位表达如下:[Xw-1, Xw-2, ... , X1, X0],它的
MSB (Most Significant Byte, 最高有效字节)为 [Xw-1, Xw-2, ... Xw-8];
LSB (Least Significant Byte, 最低有效字节)为 [X7,X6,..., X0]。
其余的字节位于MSB, LSB之间。
LSB和MSB谁位于内存的最低地址, 即谁代表该对象的地址?
这就引出了大端(Big Endian)与小端(Little Endian)的问题。
如果LSB在MSB前面, 既LSB是低地址, 则该机器是小端; 反之则是大端。
DEC (Digital Equipment Corporation,现在是Compaq公司的一部分)和Intel的机器(X86平台)一般采用小端。
IBM, Motorola(Power PC), Sun的机器一般采用大端。
当然,这不代表所有情况。有的CPU即能工作于小端, 又能工作于大端, 比如ARM, Alpha,摩托罗拉的PowerPC。 具体情形参考处理器手册。
具体这类CPU是大端还是小端,应该和具体设置有关。
(如,Power PC支持little-endian字节序,但在默认配置时是big-endian字节序)
一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,是Big Endian 的。
所以说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。因此在一个处理器系统中,有可能存在大端和小端模式同时存在的现象。这一现象为系统的软硬件设计带来了不小的 麻烦,这要求系统设计工程师,必须深入理解大端和小端模式的差别。大端与小端模式的差别体现在一个处理器的寄存器,指令集,系统总线等各个层次中。
Linux系统中,你可以在/usr/include/中(包括子目录)查找字符串BYTE_ORDER(或
_BYTE_ORDER, __BYTE_ORDER),确定其值。BYTE_ORDER中文称为字节序。这个值一般在endian.h或machine/endian.h文件中可以找到,有时在feature.h中,不同的操作系统可能有所不同。
【用函数判断系统是Big Endian还是Little Endian】
enum {FALSE = 0, TRUE = !FALSE};
typedef short BOOL;
BOOL IsBig_Endian()
//如果字节序为big-endian,返回true;
//反之为 little-endian,返回false
{
unsigned short test = 0x1122;
if(*( (unsigned char*) &test ) == 0x11)
return TRUE;
else
return FALSE;
}//IsBig_Endian()
//////////////////////////////////////////////////////////////////////////////
可以做个实验
在windows上下如下程序
#include <stdio.h>
#include <assert.h>
void main( void )
{
short test;
FILE* fp;
test = 0x3132; //(31ASIIC码的’1’,32ASIIC码的’2’)
if ((fp = fopen ("c:\\test.txt", "wb")) == NULL)
assert(0);
fwrite(&test, sizeof(short), 1, fp);
fclose(fp);
}
然后在C盘下打开test.txt文件,可以看见内容是21,而test等于0x3132,可以明显的看出来x86的字节顺序是低位在前.如果我们把这段 同样的代码放到(big-endian)的机器上执行,那么打出来的文件就是12.这在本机中使用是没有问题的.但当你把这个文件从一个big- endian机器复制到一个little-endian机器上时就出现问题了.
如上述例子,我们在big-endian的机器上创建了这个test文件,把其复制到little-endian的机器上再用fread读到一个 short里面,我们得到的就不再是0x3132而是0x3231了,这样读到的数据就是错误的,所以在两个字节顺序不一样的机器上传输数据时需要特别小 心字节顺序,理解了字节顺序在可以帮助我们写出移植行更高的代码.
正因为有字节顺序的差别,所以在网络传输的时候定义了所有字节顺序相关的数据都使用big-endian,BSD的代码中定义了四个宏来处理:
#define ntohs(n) //网络字节顺序到主机字节顺序 n代表net, h代表host, s代表short
#define htons(n) //主机字节顺序到网络字节顺序 n代表net, h代表host, s代表short
#define ntohl(n) //网络字节顺序到主机字节顺序 n代表net, h代表host, s代表 long
#define htonl(n) //主机字节顺序到网络字节顺序 n代表net, h代表host, s代表 long
举例说明下这其中一个宏的实现:
#define sw16(x) \
((short)( \
(((short)(x) & (short)0x00ffU) << | \
(((short)(x) & (short)0xff00U) >> ))
这里实现的是一个交换两个字节顺序.其他几个宏类似.
我们改写一下上面的程序
#include <stdio.h>
#include <assert.h>
#define sw16(x) \
((short)( \
(((short)(x) & (short)0x00ffU) << | \
(((short)(x) & (short)0xff00U) >> ))
#define sw32(x) \
((long)( \
(((long)(x) & (long)0x000000ff) << 24) | \
(((long)(x) & (long)0x0000ff00) << | \
(((long)(x) & (long)0x00ff0000) >> | \
(((long)(x) & (long)0xff000000) >> 24) ))
// 因为x86下面是低位在前,需要交换一下变成网络字节顺序
#define htons(x) sw16(x)
#define htonl(x) sw32(x)
void main( void )
{
short test;
FILE* fp;
test = htons(0x3132); //(31ASIIC码的’1’,32ASIIC码的’2’)
if ((fp = fopen ("c:\\test.txt", "wb")) == NULL)
assert(0);
fwrite(&test, sizeof(short), 1, fp);
fclose(fp);
}
如果在高字节在前的机器上,由于与网络字节顺序一致,所以我们什么都不干就可以了,只需要把#define htons(x) sw16(x)宏替换为 #define htons(x) (x).
一开始我在理解这个问题时,总在想为什么其他数据不用交换字节顺序?比如说我们write一块buffer到文件,最后终于想明白了,因为都是unsigned char类型一个字节一个字节的写进去,这个顺序是固定的,不存在字节顺序的问题
【大端(Big Endian)与小端(Little Endian)简介】
Byte Endian是指字节在内存中的组织,所以也称它为Byte Ordering,或Byte Order。
对于数据中跨越多个字节的对象, 我们必须为它建立这样的约定:
(1) 它的地址是多少?
(2) 它的字节在内存中是如何组织的?
针对第一个问题,有这样的解释:
对于跨越多个字节的对象,一般它所占的字节都是连续的,它的地址等于它所占字节最低地址。(链表可能是个例外, 但链表的地址可看作链表头的地址)。
比如: int x, 它的地址为0x100。 那么它占据了内存中的Ox100, 0x101, 0x102, 0x103这四个字节(32位系统,所以int占用4个字节)。
上面只是内存字节组织的一种情况: 多字节对象在内存中的组织有一般有两种约定。 考虑一个W位的整数。
它的各位表达如下:[Xw-1, Xw-2, ... , X1, X0],它的
MSB (Most Significant Byte, 最高有效字节)为 [Xw-1, Xw-2, ... Xw-8];
LSB (Least Significant Byte, 最低有效字节)为 [X7,X6,..., X0]。
其余的字节位于MSB, LSB之间。
LSB和MSB谁位于内存的最低地址, 即谁代表该对象的地址?
这就引出了大端(Big Endian)与小端(Little Endian)的问题。
如果LSB在MSB前面, 既LSB是低地址, 则该机器是小端; 反之则是大端。
DEC (Digital Equipment Corporation,现在是Compaq公司的一部分)和Intel的机器(X86平台)一般采用小端。
IBM, Motorola(Power PC), Sun的机器一般采用大端。
当然,这不代表所有情况。有的CPU即能工作于小端, 又能工作于大端, 比如ARM, Alpha,摩托罗拉的PowerPC。 具体情形参考处理器手册。
具体这类CPU是大端还是小端,应该和具体设置有关。
(如,Power PC支持little-endian字节序,但在默认配置时是big-endian字节序)
一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,是Big Endian 的。
所以说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。
Linux系统中,你可以在/usr/include/中(包括子目录)查找字符串BYTE_ORDER(或
_BYTE_ORDER, __BYTE_ORDER),确定其值。BYTE_ORDER中文称为字节序。这个值一般在endian.h或machine/endian.h文件中可以找到,有时在feature.h中,不同的操作系统可能有所不同。
big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。
用文字说明可能比较抽象,下面用图像加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:
Big Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 | 34 | 56 | 78 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 78 | 56 | 34 | 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
从上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的.
为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但 是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 J***A编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的J***A程序互通时会产生什么结果?就拿上面的 0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了J***A程序,由于J***A采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序 传给J***A程序之前有必要进行字节序的转换工作。
无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。
·BE和LE一文的补完
我在8月9号的《Big Endian和Little Endian》一文中谈了字节序的问题,原文见上面的超级链接。可是有朋友仍然会问,CPU存储一个字节的数据时其字节内的8个比特之间的顺序是否也有 big endian和little endian之分?或者说是否有比特序的不同?
实际上,这个比特序是同样存在的。下面以数字0xB4(10110100)用图加以说明。
Big Endian
msb lsb
---------------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
lsb msb
---------------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
实际上,由于CPU存储数据操作的最小单位是一个字节,其内部的比特序是什么样对我们的程序来说是一个黑盒子。也就是说,你给我一个指向0xB4这个数的 指针,对于big endian方式的CPU来说,它是从左往右依次读取这个数的8个比特;而对于little endian方式的CPU来说,则正好相反,是从右往左依次读取这个数的8个比特。而我们的程序通过这个指针访问后得到的数就是0xB4,字节内部的比特 序对于程序来说是不可见的,其实这点对于单机上的字节序来说也是一样的。
那可能有人又会问,如果是网络传输呢?会不会出问题?是不是也要通过什么函数转换一下比特序?嗯,这个问题提得很好。假设little endian方式的CPU要传给big endian方式CPU一个字节的话,其本身在传输之前会在本地就读出这个8比特的数,然后再按照网络字节序的顺序来传输这8个比特,这样的话到了接收端 不会出现任何问题。而假如要传输一个32比特的数的话,由于这个数在littel endian方存储时占了4个字节,而网络传输是以字节为单位进行的,little endian方的CPU读出第一个字节后发送,实际上这个字节是原数的LSB,到了接收方反倒成了MSB从而发生混乱。
【用函数判断系统是Big Endian还是Little Endian】
bool IsBig_Endian()
//如果字节序为big-endian,返回true;
//反之为 little-endian,返回false
{
unsigned short test = 0x1122;
if(*( (unsigned char*) &test ) == 0x11)
return TRUE;
else
return FALSE;
=======================================================================
字节序问题--大端法小端法
一、字节序定义
字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。
其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。
在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于 TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。比如,以太网头部中2字节的“以太网帧类型”,表示后面数据的类型。对于ARP请求或应答的以太网帧类型 来说,在网络传输时,发送的顺序是0x08,0x06。在内存中的映象如下图所示:
栈底 (高地址)
---------------
0x06 -- 低位
0x08 -- 高位
---------------
栈顶 (低地址)
该字段的值为0x0806。按照大端方式存放在内存中。
二、高/低地址与高低字节
首先我们要知道我们C程序映像中内存的空间布局情况:在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明,大致如下图:
----------------------- 最高内存地址 0xffffffff
| 栈底
.
. 栈
.
栈顶
-----------------------
|
|
\|/
NULL (空洞)
/|\
|
|
-----------------------
堆
-----------------------
未初始化的数据
----------------(统称数据段)
初始化的数据
-----------------------
正文段(代码段)
----------------------- 最低内存地址 0x00000000
以上图为例如果我们在栈上分配一个unsigned char buf[4],那么这个数组变量在栈上是如何布局的呢[注1]?看下图:
栈底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
栈顶 (低地址)
现在我们弄清了高低地址,接着来弄清高/低字节,如果我们有一个32位无符号整型0x12345678(呵呵,恰好是把上面的那4个字节buf看成 一个整型),那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。
高低地址和高低字节都弄清了。我们再来回顾一下Big-Endian和Little-Endian的定义,并用图示说明两种字节序:
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
Big-Endian: 低地址存放高位,如下图:
栈底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
栈顶 (低地址)
Little-Endian: 低地址存放低位,如下图:
栈底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
---------------
栈顶 (低地址)
在现有的平台上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。
三、例子
嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。
例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4001 0x12
0x4000 0x34
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4001 0x34
0x4000 0x12
32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4003 0x12
0x4002 0x34
0x4001 0x56
0x4000 0x78
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4003 0x78
0x4002 0x56
0x4001 0x34
0x4000 0x12
三、例子
测试平台 : Sun SPARC Solaris 9 和 Intel X86 Solaris 9
我们的例子是这样的:在使用不同字节序的平台上使用相同的程序读取同一个二进制文件的内容。
生成二进制文件的程序如下 :
/* gen_binary.c */
int main() {
FILE *fp = NULL;
int value = 0x12345678;
int rv = 0;
fp = fopen("temp.dat", "wb");
if (fp == NULL) {
printf("fopen error\n");
return -1;
}
rv = fwrite(&value, sizeof(value), 1, fp);
if (rv != 1) {
printf("fwrite error\n");
return -1;
}
fclose(fp);
return 0;
}
读取二进制文件的程序如下:
int main() {
int value = 0;
FILE *fp = NULL;
int rv = 0;
unsigned char buf[4];
fp = fopen("temp.dat", "rb");
if (fp == NULL) {
printf("fopen error\n");
return -1;
}
rv = fread(buf, sizeof(unsigned char), 4, fp);
if (rv != 4) {
printf("fread error\n");
return -1;
}
memcpy(&value, buf, 4); // or value = *((int*)buf);
printf("the value is %x\n", value);
fclose(fp);
return 0;
}
测试过程:
(1) 在 SPARC 平台下生成 temp.dat 文件
在 SPARC 平台下读取 temp.dat 文件的结果:
the value is 12345678
在 X86 平台下读取 temp.dat 文件的结果:
the value is 78563412
(1) 在 X86 平台下生成 temp.dat 文件
在 SPARC 平台下读取 temp.dat 文件的结果:
the value is 78563412
在 X86 平台下读取 temp.dat 文件的结果:
the value is 12345678
[ 注 1]
buf[4] 在栈的布局我也是通过例子程序得到的:
int main() {
unsigned char buf[4];
printf("the buf[0] addr is %x\n", buf);
printf("the buf[1] addr is %x\n", &buf[1]);
return 0;
}
output:
SPARC 平台:
the buf[0] addr is ffbff788
the buf[1] addr is ffbff789
X86 平台:
the buf[0] addr is 8047ae4
the buf[1] addr is 8047ae5
两个平台都是 buf[x] 所在地址高于 buf[y] (x > y) 。
如何判断系统是Big Endian还是Little Endian?
在/usr /include/中(包括子目录)查找字符串BYTE_ORDER(或_BYTE_ORDER, __BYTE_ORDER),确定其值。这个值一般在endian.h或machine/endian.h文件中可以找到,有时在feature.h中, 不同的操作系统可能有所不同。一般来说,Little Endian系统BYTE_ORDER(或_BYTE_ORDER,__BYTE_ORDER)为1234,Big Endian系统为4321。大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,是Big Endian 的。本质上说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。
Processor OS Order
x86 (Intel, AMD, … ) All little-endian
DEC Alpha All little-endian
HP-PA NT little-endian
HP-PA UNIX big-endian
SUN SPARC All? big-endian
MIPS NT little-endian
MIPS UNIX big-endian
PowerPC NT little-endian
PowerPC non-NT big-endian
RS/6000 UNIX big-endian
Motorola m68k All big-endian
迄今已分析出来了sybase中索引(indid>1)的物理存储结构。
索引结构是B-Tree类型的。最顶部叫做根(root),最底层称为叶子(leaf)。一个表可能建有好几个非聚簇索引,这时indid依次为2,3,。。。递增。
对于一个索引,比如indid=2的那个。索引树状结构是分层次的,在sybase数据存储中用level表示,根部级别最高,叶子的级别最低。叶 子(leaf)的级别level为0,往上索引层level为1,再往上位2,。。。最后到达顶部root级别为(N-1,N为所有的层次数)。
不管APL还是DOL表,索引的每层(level)上的页面都是前后链接起来的,这一点有点像APL表中的数据页面上的前、后页链(data page link)。
以下简要演示分析索引结构的过程。
1.
设定成在终端显示dbcc结果信息。
1 2 | dbcc traceon(3604) go |
2.
查看syspartitions表的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1> select *from sysobjects 2> where name='PartitionTestTable' 3> go name id uid type userstat sysstat indexdel schemacnt sysstat2 crdate expdate deltrig instrig updtrig seltrig ckfirst cache audflags objspare versionts loginame identburnmax spacestate erlchgts ----------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------- ----------- ----------- ---- -------- ------- -------- --------- ----------- -------------------------- -------------------------- ----------- ----------- ----------- ----------- ----------- ------ ----------- ----------- -------------------------- ------------------------------ ----------------------------------------- ---------- ------------------ PartitionTestTable 1223672376 1 U 0 99 2 0 73728 Feb 24 2010 4:43PM Feb 24 2010 4:43PM 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL (1 row affected) 1> select * from syspartitions 2> where id = 1223672376 3> go name indid id partitionid segment status datoampage indoampage firstpage rootpage data_partitionid crdate cdataptnname ----------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------- ------ ----------- ----------- ------- ----------- ----------- ----------- ----------- ----------- ---------------- -------------------------- --------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------ zhang 0 1223672376 1239672433 1 0 61288 0 61289 61997 0 Feb 24 2010 4:43PM NULL liu 0 1223672376 1255672490 1 0 61296 0 61297 62124 0 Feb 24 2010 4:43PM NULL wang 0 1223672376 1271672547 1 0 61304 0 61305 62260 0 Feb 24 2010 4:43PM NULL li 0 1223672376 1287672604 1 0 61312 0 61313 62385 0 Feb 24 2010 4:43PM NULL idx_PartitionTestTable_id_1431673117 2 1223672376 1431673117 1 2 0 62465 67256 66248 0 Mar 1 2010 11:19AM NULL idx_PartitionTestTable_name_1479673288 3 1223672376 1479673288 1 2 0 62721 69816 69386 0 Mar 1 2010 6:03PM NULL (6 rows affected) 1> |
表PartitionTestTable是在其上的id列建了4个分区的分区表,它有2个索引。idx_PartitionTestTable_id对id列索引,idx_PartitionTestTable_name对name列索引。
我们就分析idx_PartitionTestTable_id这个索引吧。通过syspartitions表我们可以得到四个比较有用的 datoampage,indoampage, firstpage ,rootpage。分别表示数据对象分配页的页号,索引对象分配页的页号,
索引叶子层上的第一页,索引根部的页号。(堆表信息中的firstpage,rootpage意思有些不同。分别表示:数据页的第一个、最后一页。)
有:datoampage=0,indoampage=62465,firstpage= 67256,rootpage=66248.
对于indoampage索引对象分配页,可以这么查看。(PartitionTestTable的objid为: 1223672376)
dbcc listoam(4,1223672376,2)
3.可以看出索引idx_PartitionTestTable_id在14个对象分配页allocation page上的分配情况如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1> dbcc listoam(4,1223672376,2) 2> go ----------------------------------------------------------------------------- Partition id: 1431673117 indid: 2 prevpg: 62465 nextpg: 62465 OAM pg cnt: 1 Entry cnt: 14 Row count information is not maintained for index pages. Used pgs: 716 Unused pgs: 11 Attribute entries: 10 OAM status bits set: (0x8000 (PG_OAMPG), 0x0008 (PG_OAMATTRIB), 0x0004 (PG_OAMSORT)) LAST SCANNED OAM PAGE: 0 ALLOCATION HINTS : 62465 0 0 0 0 0 0 0 0 0 0 0 0 0 0 OAM pg # 1: 62465 has the following 14 entries (allocpg:used/unused): [ 0] 62464: 9/ 6 63232: 24/ 0 63744: 8/ 0 64256: 0/ 0 [ 4] 64768: 16/ 0 65024: 16/ 0 65280: 16/ 0 65536: 16/ 0 [ 8] 65792:152/ 0 66048:240/ 0 66304: 96/ 0 66560: 48/ 0 [ 12] 66816: 40/ 0 67072: 35/ 5 There are 1 entries with zero used/unused values. ---- End of OAM chain for partition 1431673117 ---- DBCC execution completed. If DBCC printed error messages, contact a user with System Administrator (SA) role. |
(此处,暂时不解释以上结果中的情况!)
4.现在回到索引上,先从根部分析。rootpage=66248。
查看66248页上的16进制数据。
dbcc page(4,66248,1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1> dbcc page(4,66248,1) 2> go Page not found in Cache: default data cache. Page read from disk. BUFFER: Buffer header for buffer 0x28288000 (Mass head) page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000 bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4 bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=132496 vdisk=0x21DE1CB4 ] bmass_head=0x28288000 bmass_tail=0x28288000 bcache_desc=0x2828B3F0 (cache name='default data cache') bpool_desc=0x00000000 bdbtable=0x00000000 Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0 bmass_size=4096 (4K pool) bunref_cnt=0 bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED)) bbuf_stat=0x0 (0x00000000) Buffer blpageno=66248 bpg_size=4k Mass blpageno=66248 (Buffer slot #: 0) bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0 bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000 Latch and the wait queue: Latch (address: 0x28288020) latchmode: 0x0 (FREE_LATCH) latchowner: 0 latchnoofowners: 0 latchwaitq: 0x00000000 latchwaitqt: 0x00000000 Latch wait queue: PAGE HEADER: Page header for page 0x28287000 pageno=66248 nextpg=0 prevpg=0 ptnid=1431673117 timestamp=0000 0040a817 lastrowoff=62 level=2 indid=2 freeoff=77 minlen=15 page status bits: 0x80 (0x0080 (PG_FIXED)) DATA: Offset 32 - row length=15 # varlen cols=0 Child page ID=67258 28287020 ( 0): 00be8301 00aff000 004100ba 060100 .........A..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 47 - row length=15 # varlen cols=0 Child page ID=65823 2828702F ( 0): 00be8301 00aff000 0041001f 010100 .........A..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 62 - row length=15 # varlen cols=0 Child page ID=66990 2828703E ( 0): 007b0703 00f0f200 009d00ae 050100 .{............. Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] OFFSET TABLE: DBCC execution completed. If DBCC printed error messages, contact a user with System Administrator (SA) role. 1> |
此时,可以看出索引根部的级别level为2。 也就是说索引还有中间层level=1和叶子层level=0.
看第二行数据,
Offset 47 - row length=15 # varlen cols=0 Child page ID=65823
2828702F ( 0): 00be8301 00aff000 0041001f 010100 .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
它的子页面号是:65823。
再来查看65823的页面数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1> dbcc page(4,65823,1) 2> go Page not found in Cache: default data cache. Page read from disk. BUFFER: Buffer header for buffer 0x28288000 (Mass head) page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000 bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4 bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=131646 vdisk=0x21DE1CB4 ] bmass_head=0x28288000 bmass_tail=0x28288000 bcache_desc=0x2828B3F0 (cache name='default data cache') bpool_desc=0x00000000 bdbtable=0x00000000 Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0 bmass_size=4096 (4K pool) bunref_cnt=0 bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED)) bbuf_stat=0x0 (0x00000000) Buffer blpageno=65823 bpg_size=4k Mass blpageno=65823 (Buffer slot #: 0) bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0 bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000 Latch and the wait queue: Latch (address: 0x28288020) latchmode: 0x0 (FREE_LATCH) latchowner: 0 latchnoofowners: 0 latchwaitq: 0x00000000 latchwaitqt: 0x00000000 Latch wait queue: PAGE HEADER: Page header for page 0x28287000 pageno=65823 nextpg=66990 prevpg=67258 ptnid=1431673117 timestamp=0000 0040a817 lastrowoff=4052 level=1 indid=2 freeoff=4067 minlen=15 page status bits: 0x80 (0x0080 (PG_FIXED)) DATA: Offset 32 - row length=15 # varlen cols=0 Child page ID=65822 28287020 ( 0): 00be8301 00aff000 0041001e 010100 .........A..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 47 - row length=15 # varlen cols=0 Child page ID=66249 2828702F ( 0): 002f8501 0039f100 003300c9 020100 ./...9...3..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 62 - row length=15 # varlen cols=0 Child page ID=66250 2828703E ( 0): 00a08601 007bf100 00a700ca 020100 .....{......... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 77 - row length=15 # varlen cols=0 Child page ID=66251 2828704D ( 0): 00118801 00f3f000 00c800cb 020100 ............... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 92 - row length=15 # varlen cols=0 Child page ID=66252 2828705C ( 0): 00828901 00b0f000 00d100cc 020100 ............... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 107 - row length=15 # varlen cols=0 Child page ID=66253 2828706B ( 0): 00f38a01 003af100 00b500cd 020100 .....:......... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] |
此页面65823是索引的中间层level=1.看第一行的数据。
Offset 32 - row length=15 # varlen cols=0 Child page ID=65822
28287020 ( 0): 00be8301 00aff000 0041001e 010100 .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
页面:66248上的第二行就是指向该行。
继续查看它的子页面上的数据,65822。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1> dbcc page(4,65822,1) 2> go Page not found in Cache: default data cache. Page read from disk. BUFFER: Buffer header for buffer 0x28288000 (Mass head) page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000 bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4 bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=131644 vdisk=0x21DE1CB4 ] bmass_head=0x28288000 bmass_tail=0x28288000 bcache_desc=0x2828B3F0 (cache name='default data cache') bpool_desc=0x00000000 bdbtable=0x00000000 Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0 bmass_size=4096 (4K pool) bunref_cnt=0 bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED)) bbuf_stat=0x0 (0x00000000) Buffer blpageno=65822 bpg_size=4k Mass blpageno=65822 (Buffer slot #: 0) bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0 bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000 Latch and the wait queue: Latch (address: 0x28288020) latchmode: 0x0 (FREE_LATCH) latchowner: 0 latchnoofowners: 0 latchwaitq: 0x00000000 latchwaitqt: 0x00000000 Latch wait queue: PAGE HEADER: Page header for page 0x28287000 pageno=65822 nextpg=66249 prevpg=65821 ptnid=1431673117 timestamp=0000 0040a817 lastrowoff=4080 level=0 indid=2 freeoff=4091 minlen=11 page status bits: 0x82 (0x0080 (PG_FIXED), 0x0002 (PG_LEAF)) DATA: Offset 32 - row length=11 # varlen cols=0 Data page RID=(61615, 65) 28287020 ( 0): 00be8301 00aff000 004100 .........A. Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 43 - row length=11 # varlen cols=0 Data page RID=(61752, 198) 2828702B ( 0): 00bf8301 0038f100 00c600 .....8..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] Offset 54 - row length=11 # varlen cols=0 Data page RID=(61818, 239) 28287036 ( 0): 00c08301 007af100 00ef00 .....z..... Row-Offset table for variable-length columns: [<varcol number>, <offset from start of the row>, <varcol length>] |
还是分析页面上的第一行。索引叶子层直接指向了数据页面,某一页面上的某一行。
Offset 32 - row length=11 # varlen cols=0 Data page RID=(61615, 65)
28287020 ( 0): 00be8301 00aff000 004100 .........A.
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
继续往下,dbcc page(4,61615,1)找到第65行数据。
Offset 1072 - row ID=65 row length=16 # varlen cols=1
28287430 ( 0): 0141be83 0100 1000 7a68616e 67020d08 .A......zhang...
28287440 ( 16):
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
[1, 8, 5]
可以看出00be8301 00 aff000 004100中的be8301 00 和0141be83 01001000 7a68616e 67020d08中的
be83 0100 是一致的。也就是说索引中间层level=1是指向叶子层上的第一页。并且包含索引键的数据99262。
从16进制数据中分析出来,页61615第65行的数据为:id=99262,name='zhang'。
暂时就分析这么多。可能有些地方说的不太明白。见谅!
————————————————————————————————
—- 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
—- 转载务必注明原始出处 : http://www.dbainfo.net
—- 关键字:索引 存储结构 分析 非聚簇 index storage non-clustered
————————————————————————————————