维生素C.net

IronRuby, CLR/DLR, Debugging
posts - 62, comments - 172, trackbacks - 10, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

2008年8月14日

在年初的时候做了一个很小的支持故障转移的简陋的缓存,是用c在ubuntu上实现的,后来希望这个c程序有非常好的移植性,就把c的说明文档大体看了一下,才发现了好多学习c时的误区。

想起前两天跟同学校的几位同学聊起几个技术相关的问题,最大的感觉就是大家都越来越忽视程序了,眼高手低和粗心大意其实不是“失误”或“毛病”,而是“很严重的错误”。

每次遇到说java要不.net好的人,我向来第一感觉都是挺佩服的——能把这两个东东看到很透彻的人水平绝对不差,肯定是我老师级别的,我可以像他学不少东西的——可是几乎每次结果都是让我以“sorry,有点事,离开一下”来中止这段谈话。更有一个我的朋友说“技术牛不牛无所谓,知道大体怎么回事,业务熟就行了”。中国软件业为何差?这样的意识形态绝对不是一两个人生而有之的。

言归正传,我这位同学的宣称“可移植”的c中有几句是这样的:

 

Code

 

打眼一看,这是一段把用户输入转换成小写的功能。可是这三行代码能“任意移植”吗?

答案肯定是不能——tolower()和toupper()在早期的c里是被实现为宏的。这个宏是个有利有弊的问题,尤其是在不同版本的c里,宏的使用都是个老大难的问题。比如说tolower(),他的实现如果是:

 

Code

 

那就糟糕了,上面的程序如果输入的就是小写,那得到的就是垃圾数据了。

冰山一角,我问了那位同学是否知道a+=b在有的c实现里也可以写成a=+b啊,得到的答案是沉默。我又问了一个知道a=/ *b和a=/*b有什么区别吗?答案还是沉默。

写程序,切忌在喧闹的酒吧里写——浮躁的环境和时代附加给代码的只可能是你的无知。So,如果你认为你是一个程序员,请尊重你的职业。

posted @ 2008-08-14 01:00 new 维生素C.net() 阅读(83) | 评论 (3)编辑

2008年8月6日

前段时间项目遇到一些问题,抓了一个dump后拿回家里的机器上分析。按着方法一步一步走,走到!clrstack的时候,问题出现了——看不到托管环境下的method name。我觉得这这!clrstack看不到method name可真没什么作用了。随后请教了几个朋友,都说没碰到过着情况。

第二天去了公司先打开windbg,open这个dump,载入sos后先来一个~*e!clrstack。邪门,method name都出来了。

从操作系统,windbg版本,symbols等几个方面都下手分析了一下,未果。问人吧,问了一圈都没有解决。问了熊力大哥,他说他可以看到,说明问题肯定不奇怪,而且肯定是某个细节的问题。挂虚拟机,测之,问题依旧,大悦,终于出问题了。

后来我把我公司机器上的sos和家里机器的sos拿过来比较,大小不一样,用!eeversion来看,版本号确实不一样。问题解决——选用合适的版本!

 

--the not work one--
0:000> .load c:\windows\microsoft.net\framework\v2.0.50727\sos.dll
0:000> !eeversion
2.0.50727.1433 retail
Workstation mode
SOS Version: 2.0.50727.3031 retail build

 

--the work one--
0:000> .load ../sos.dll
0:000> !eeversion
2.0.50727.1433 retail
Workstation mode
SOS Version: 2.0.50727.1433 retail build

 

--not work one result--
0:000> ~*e!clrstack
OS Thread Id: 0x11cc (0)
ESP       EIP    
0012f440 7c9585ec [NDirectMethodFrameStandalone: 0012f440]
0012f450 67a241d2
0012f47c 00c100a7
0012f69c 79e7c74b [GCFrame: 0012f69c]
OS Thread Id: 0x139c (1)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x994 (2)
Failed to start stack walk: 80004005
OS Thread Id: 0xaec (3)
Failed to start stack walk: 80004005
OS Thread Id: 0xc14 (4)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x9bc (5)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0xe3c (6)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x11b0 (7)
ESP       EIP    
0421f654 7c9585ec [HelperMethodFrame: 0421f654]
0421f6a8 00c13f48
0421f6c4 7964a312
0421f6cc 79373ecd
0421f6e4 7940647a
0421f90c 79e7c74b [GCFrame: 0421f90c]

 

--work one result--
0:000> ~*e!clrstack
OS Thread Id: 0x11cc (0)
ESP       EIP    
0012f440 7c9585ec [NDirectMethodFrameStandalone: 0012f440] System.ServiceProcess.NativeMethods.StartServiceCtrlDispatcher(IntPtr)
0012f450 67a241d2 System.ServiceProcess.ServiceBase.Run(System.ServiceProcess.ServiceBase[])
0012f47c 00c100a7 CSDN.IM.JobTimeWindowsServices.Program.Main()
0012f69c 79e7c74b [GCFrame: 0012f69c]
OS Thread Id: 0x139c (1)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x994 (2)
Failed to start stack walk: 80004005
OS Thread Id: 0xaec (3)
Failed to start stack walk: 80004005
OS Thread Id: 0xc14 (4)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x9bc (5)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0xe3c (6)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x11b0 (7)
ESP       EIP    
0421f654 7c9585ec [HelperMethodFrame: 0421f654] System.Threading.Thread.SleepInternal(Int32)
0421f6a8 00c13f48 Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Storage.ConfigurationChangeWatcher.Poller(System.Object)
0421f6c4 7964a312 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
0421f6cc 79373ecd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
0421f6e4 7940647a System.Threading.ThreadHelper.ThreadStart(System.Object)
0421f90c 79e7c74b [GCFrame: 0421f90c]

 

remember: 选用匹配的版本

 

-----------

后来为了弄清楚问题,发邮件问了Tom,他给给的回复是:

So the problem here is that we do not guarantee that newer versions of SOS will be able to debug older versions of CLR.  You must match the version of SOS to the version of the runtime (unless we are explicitly giving them private bits for SOS to fix a bug in it).  From the output below, !eeversion is telling you that the one that won’t walk the stack does not match the runtime’s version.  This is why it won’t walk the stack.
We always try to make SOS backwards compatible, but it’s not something we guarantee.

 

 

posted @ 2008-08-06 01:37 new 维生素C.net() 阅读(985) | 评论 (3)编辑

2008年8月3日

exec master..xp_cmdshell
'bcp "Select routine_definition from OnlyVC.information_Schema.routines order by routine_name" queryout "d:\1.sql" -c –T'

加粗部分为db的name

执行前要注意2个地方:

1.先执行

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure  'show advanced options', 0

否则会遇到下面的错误:

Msg 15281, Level 16, State 1, Procedure xp_cmdshell, Line 1
SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online.

2.添加-T参数:

否则会遇到下面的错误:

err1

User name not provided, either use -U to provide the user name or use -T for Trusted Connection

posted @ 2008-08-03 16:12 new 维生素C.net() 阅读(30) | 评论 (0)编辑

2008年7月29日

编译源代码运行方式:

1.svn://rubyforge.org/var/svn/ironruby
IronRuby Get

IronRuby Get Done

2.打开\IronRuby\IronRuby.sln,需要注意的是Load Prj normally
Security Warning
然后编译整个项目

3.打开Visual Studio xx Command Prompt(run as administrator),到\IronRuby\(如果是debug模式编译的话)下执行runfirst.cmd

4.方便期间,在系统环境变量里添加\IronRuby\Build\Debug\(如果是以debug方式编译)的path. 新开一个cmd窗口.输入ir,通常情况下可以看到:
image

OK,IronRuby运行起来了

-----------

做一个简单的测试:

1.用notepad新建一个Hi.rb,内容如下:
class Hi #类的名称与Hi.rb的主文件名要一致,后面需要
   def say
     puts “hi, fanweixiao”
   end
end

2.再创建一个test.rb,内容:
require “Hi” #会自动寻找Hi.rb文件

h=Hi.new
h.say

3.运行ir test.rb. 能看到结果了.

 

如果不清楚可以查看更为详细的原文

posted @ 2008-07-29 02:32 new 维生素C.net() 阅读(58) | 评论 (0)编辑

2008年7月28日

D:\Software\svn15\bin>sc create svnservice12 binpath= "D:\Software\svn15\bin\svnserve.exe --service -r D:\Svn_reposities" displayname= "SubversionRepository3" depend= Tcpip start= auto

在网上google了好几个,有的写法错了,有的是用-d(deamon守护模式)来启动的. 这里记录一个正确的.

posted @ 2008-07-28 02:12 new 维生素C.net() 阅读(29) | 评论 (0)编辑

2008年7月27日

情景1:
安装完后访问,报Could not connect to Virtual Server.  Access Denied.  Please contact Virtual Server administrator to set the required permissions to manage Virtual Server.  You can specify an alternate Virtual Server below.的错误
原因:
IIS7中需要安装windows authentication

情景2:
安装完后访问,提示下载exe文件,而不是在浏览器里展示
IIS7中需要安装CGI支持

关键步骤:

  1. 安装iis7,至少包含windows authentication和CGI
  2. 在virtual server的site下配置Authentication,disable除windows authentication外的其他验证方式
  3. 在Handler Mapping下启用CGI-exe,确保excute权限.

没有x64,没有Hyper-V,痛苦.

posted @ 2008-07-27 03:49 new 维生素C.net() 阅读(67) | 评论 (0)编辑

2008年7月22日

如果遇到了性能问题,在使用debug之前分析问题较为不错的一个工具就是perfmon.解决问题最好的方法是思考,这也是熊力大哥在其书中一直在强调的.

如果您的网站遇到下面的几种情形,那还是先看看perfmon里GC相关的东西吧:

  1. cpu占用高,内存占用不高.
  2. cpu和内存占用都比较高
  3. cpu和内存占用都不高,但是网站响应很慢

打开perfmon找到.NET CLR Memory后下面有好几个counter,从哪个开始看呢?

1) % Time in GC

这个值是说从上一次GC结束到当前这次GC的时间的百分比. 比如上次GC结束时经历了100w个循环,当前的GC消耗是50w个循环,这个计数器的值就是50%. 看perfmon的各个counter来推测究竟是什么问题,主要有两类情况,第一类需要看counter到变化趋势,第二类需要看到是counter到值.这里对待第2类情况引入一个"健康值"的概念.当然这些只是大方向上来说到,并不是100%到准确的适应大多数情况.

那么这个值为多少合适呢? 一般来说如果这个值>50%了我们应该去检查一下托管堆的问题.如果这个值不大,没有太大的必要去优化程序了.

2)Allocated Bytes/sec

如果认为在GC上花费的时间太多了,接下来应该看看Allocated Bytes/sec这个counter,它显示了分配速率.需要注意到是这个counter到值在分配速率很低的情况下其实是不准确的,这个值只有在每次GC开始的时候才会被更新,如果perfmon到取样频率(默认是1秒)大于GC的频率的时候,这个值就不太容易说明问题了。

当有分配请求不能被完成时,会触发GC:

  1. Gen0满了,不能满足最后一次的小对象的分配请求
  2. LOH满了,不能满足最后一次的大对象分配请求

所以当GC开始的时候会更新该计数器到值——将Gen0和LOH想加的和加到这个值上,然后与上一次的值相加再除以时间间隔。得到的就是这个分配速率。

举个例子:默认情况下perfmon1秒更新一次数据,在第1秒Gen0 GC因为需要分配100k而触发,所以再第1秒末这个值是(100k-0k)/1sec,是100k/sec。在第2秒没有GC发生,记录的值还是100k,那么第2秒末该值就是(100k-100k)/1sec,是0k/sec,第3秒Gen0 GC又被触发总共被分配了200k,所以在第3秒末的时候这个值是(200k-100k)/1sec,是100k/sec。

从上面到例子能看到如果说GC发生的不是非常频繁的话这个值应该是0k/sec的。

3)Large Object Heap Size

这个值只是记录在LOH里的bytes。

OK。到这一步为主,我们可以看出导致GC做大量工作的一个关键因素就是较高的分配速率。大家都知道GC是分Generation的,从Gen0到Gen2,如果一个对象在Gen0到时候就死了,我们况且成它为“夭折”(die young),另一类生命力看似顽强但是到了Gen2立刻挂掉的,我们称之为“中年危机”(die at Gen2)。

所以如果都在GC Gen0完成后就结束工作了,花在GC上的时间百分比是不会高的。毕竟Gen0到GC只会占用非常短暂的时间。

但是Gen2的GC就不这样了,它会从Gen0到Gen2,再加上LOH的。LOH的GC也是很消耗资源的工作,但是并没有只针对LO的回收,所以即使LOH还有空间可供分配,但是Gen2满了,也会导致LOH跟着一起遭殃。

通常来说这三个代的GC速率在100:10:1是不错的。

4)# Gen X Collections

X到值为0,1和2。需要注意的一点是Gen1会一次性的回收Gen0和Gen1。

如果有大量的Gen2上的GC,就意味着有大量的对象存活了太长时间,但是还没长到他们要一直在Gen2里生存。如果看到了GC消耗了很多时间但是分配速率却不高的话,最大的可能就是很多对象在不断的从Gen0到Gen2被不断的提升。

5)Promoted Memory from Gen 0/1和 Promoted Finalization - Memory from Gen 0

这三个值是看提升(promotion)情况的。被finalization引发的对象的提升要看后者,是不包括在前面两个counter里的。但是后者虽然说是from Gen 0的,但是其实同时包含了Gen0和Gen1的。

这时可能出现一种最坏的情况:一个对象存活了很久,最终被提升到Gen2,但是一进入Gen2立刻就死掉了,也就是上述的“中年危机”。当遇到这个情况Promoted Memory from Gen1到只是比较高的,而且有大量的Gen2 GC。

需要注意到是当一个finalizable的对象存活时,所以他引用的对象也都是存活的,Promoted Finalization-Memory from Gen0的计数器也包含了这些对象。

6)Gen 1/2 heap size

当看到这些提升相关的计数器的值比较高时,应该看看这两个counter。他们的意思从名字就能看出。

需要注意Gen 0 heap size到值是假的,它其实是一个预算,指示下一次什么时候进行GC的。

Gen0和Gen1都很小,从256k到几兆。

7)# Total committed Bytes和# Total reserved Bytes

# Total committed Bytes= Gen0 heap size + Gen 1 heap size + Gen 2 heap size + LOH size

后者到值要比前者的值大.

8)# Induce GC

如果看到这个值比较高那就比较惨了,检查代码中GC.Collect()是不是调用了太多了.这种使用和设置IIS检测到memory涨到一定程度自动回收一样,都不是真正解决问题的方法.

 

参考:
http://msdn.microsoft.com/en-us/library/0xy59wtx.aspx
http://msdn.microsoft.com/en-us/library/f144e03t(VS.80).aspx
http://blogs.msdn.com/maoni
http://msdn.microsoft.com/en-us/library/bb802825.aspx

posted @ 2008-07-22 13:17 new 维生素C.net() 阅读(69) | 评论 (0)编辑

dd if=/dev/zero of=/empty_file; rm empty_file

posted @ 2008-07-22 01:30 new 维生素C.net() 阅读(55) | 评论 (0)编辑

2008年7月20日

AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
           
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
                   
aName,
                   
AssemblyBuilderAccess.RunAndSave);

           
// For a single-module assembly, the module name is usually
            // the assembly name plus an extension.
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

           
TypeBuilder tb = mb.DefineType(
                "MyDynamicType"
,
                
TypeAttributes.Public);

           
// Add a private field of type int (Int32).
            FieldBuilder fbNumber = tb.DefineField(
                "m_number"
,
               
typeof(int),
               
FieldAttributes.Private);

           
// Define a constructor that takes an integer argument and
            // stores it in the private field.
            Type[] parameterTypes = { typeof(int) };
           
ConstructorBuilder ctor1 = tb.DefineConstructor(
               
MethodAttributes.Public,
               
CallingConventions.Standard,
               
parameterTypes);

           
ILGenerator ctor1IL = ctor1.GetILGenerator();
           
// For a constructor, argument zero is a reference to the new
            // instance. Push it on the stack before calling the base
            // class constructor. Specify the default constructor of the
            // base class (System.Object) by passing an empty array of
            // types (Type.EmptyTypes) to GetConstructor.
            ctor1IL.Emit(OpCodes.Ldarg_0);
           
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
           
// Push the instance on the stack before pushing the argument
            // that is to be assigned to the private field m_number.
            ctor1IL.Emit(OpCodes.Ldarg_0);
           
ctor1IL.Emit(OpCodes.Ldarg_1);
           
ctor1IL.Emit(OpCodes.Stfld, fbNumber);
           
ctor1IL.Emit(OpCodes.Ret);

           
// Define a default constructor that supplies a default value
            // for the private field. For parameter types, pass the empty
            // array of types or pass null.
            ConstructorBuilder ctor0 = tb.DefineConstructor(
               
MethodAttributes.Public,
               
CallingConventions.Standard,
               
Type.EmptyTypes);

           
ILGenerator ctor0IL = ctor0.GetILGenerator();
           
// For a constructor, argument zero is a reference to the new
            // instance. Push it on the stack before pushing the default
            // value on the stack, then call constructor ctor1.
            ctor0IL.Emit(OpCodes.Ldarg_0);
           
ctor0IL.Emit(OpCodes.Ldc_I4_S, 42);
           
ctor0IL.Emit(OpCodes.Call, ctor1);
           
ctor0IL.Emit(OpCodes.Ret);

           
// Define a property named Number that gets and sets the private
            // field.
            //
            // The last argument of DefineProperty is null, because the
            // property has no parameters. (If you don't specify null, you must
            // specify an array of Type objects. For a parameterless property,
            // use the built-in array with no elements: Type.EmptyTypes)
            PropertyBuilder pbNumber = tb.DefineProperty(
                "Number"
,
               
PropertyAttributes.HasDefault,
               
typeof(int),
               
null);

           
// The property "set" and property "get" methods require a special
            // set of attributes.
            MethodAttributes getSetAttr = MethodAttributes.Public |
               
MethodAttributes.SpecialName | MethodAttributes.HideBySig;

           
// Define the "get" accessor method for Number. The method returns
            // an integer and has no arguments. (Note that null could be
            // used instead of Types.EmptyTypes)
            MethodBuilder mbNumberGetAccessor = tb.DefineMethod(
                "get_Number"
,
               
getSetAttr,
               
typeof(int),
               
Type.EmptyTypes);

           
ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();
           
// For an instance property, argument zero is the instance. Load the
            // instance, then load the private field and return, leaving the
            // field value on the stack.
            numberGetIL.Emit(OpCodes.Ldarg_0);
           
numberGetIL.Emit(OpCodes.Ldfld, fbNumber);
           
numberGetIL.Emit(OpCodes.Ret);

           
// Define the "set" accessor method for Number, which has no return
            // type and takes one argument of type int (Int32).
            MethodBuilder mbNumberSetAccessor = tb.DefineMethod(
                "set_Number"
,
               
getSetAttr,
               
null,
               
new Type[] { typeof(int) });

           
ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator();
           
// Load the instance and then the numeric argument, then store the
            // argument in the field.
            numberSetIL.Emit(OpCodes.Ldarg_0);
           
numberSetIL.Emit(OpCodes.Ldarg_1);
           
numberSetIL.Emit(OpCodes.Stfld, fbNumber);
           
numberSetIL.Emit(OpCodes.Ret);

           
// Last, map the "get" and "set" accessor methods to the
            // PropertyBuilder. The property is now complete.
            pbNumber.SetGetMethod(mbNumberGetAccessor);
           
pbNumber.SetSetMethod(mbNumberSetAccessor);

           
// Define a method that accepts an integer argument and returns
            // the product of that integer and the private field m_number. This
            // time, the array of parameter types is created on the fly.
            MethodBuilder meth = tb.DefineMethod(
                "MyMethod"
,
               
MethodAttributes.Public,
               
typeof(int),
               
new Type[] { typeof(int) });

           
ILGenerator methIL = meth.GetILGenerator();
           
// To retrieve the private instance field, load the instance it
            // belongs to (argument zero). After loading the field, load the
            // argument one and then multiply. Return from the method with
            // the return value (the product of the two numbers) on the
            // execution stack.
            methIL.Emit(OpCodes.Ldarg_0);
           
methIL.Emit(OpCodes.Ldfld, fbNumber);
           
methIL.Emit(OpCodes.Ldarg_1);
           
methIL.Emit(OpCodes.Mul);
           
methIL.Emit(OpCodes.Ret);

           
// Finish the type.
            Type t = tb.CreateType();

           
// The following line saves the single-module assembly. This
            // requires AssemblyBuilderAccess to include Save. You can now
            // type "ildasm MyDynamicAsm.dll" at the command prompt, and
            // examine the assembly. You can also write a program that has
            // a reference to the assembly, and use the MyDynamicType type.
            //
            ab.Save(aName.Name + ".dll");

           
// Because AssemblyBuilderAccess includes Run, the code can be
            // executed immediately. Start by getting reflection objects for
            // the method and the property.
            MethodInfo mi = t.GetMethod("MyMethod");
           
PropertyInfo pi = t.GetProperty("Number");

           
// Create an instance of MyDynamicType using the default
            // constructor.
            object o1 = Activator.CreateInstance(t);

           
// Display the value of the property, then change it to 127 and
            // display it again. Use null to indicate that the property
            // has no index.
            Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null));
           
pi.SetValue(o1, 127, null);
           
Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, null));

           
// Call MyMethod, passing 22, and display the return value, 22
            // times 127. Arguments must be passed as an array, even when
            // there is only one.
            object[] arguments = { 22 };
           
Console.WriteLine("o1.MyMethod(22): {0}",
               
mi.Invoke(o1, arguments));

           
// Create an instance of MyDynamicType using the constructor
            // that specifies m_Number. The constructor is identified by
            // matching the types in the argument array. In this case,
            // the argument array is created on the fly. Display the
            // property value.
            object o2 = Activator.CreateInstance(t,
               
new object[] { 5280 });
           
Console.WriteLine("o2.Number: {0}", pi.GetValue(o2, null));
用完要unload或者只创建一次。否则可能导致high memory

posted @ 2008-07-20 23:14 new 维生素C.net() 阅读(35) | 评论 (0)编辑

2008年7月18日

看了http://wiki.centos.org/HowTos/Subversion上的tutorial. 但是完全按照这个教程来做,必须忽略中间的一个问题:

在完成第1、2步后, tutorial上说:

Go test out whether or not you can access your repository from a web browser: http://yourmachine/repos. You should get a popup box asking for a username and password. If so, type in your credentials and you should be displayed with a Revision 0:/ page.

但是事实是你得到的只能是Forbidden, don't have permission的错误:

Forbidden

You don't have permission to access /repos on this server.


Apache/2.2.3 (CentOS) Server at dev.onlyvc.cn Port 80


这里正确的步骤是:

  1. /etc/conf.d/subversion.conf里配置的SVNPath /var/www/svn/repos是根目录
  2. 在/var/www/svn/repos/下用svnadmin create onlyvc来创建一个库
  3. chown --recursive apache.apache onlyvc给予apache的权限
  4. service httpd restart来重启apache
  5. 访问http://localhost/repos/onlyvc

这样才是正确的能看到Revision 1的做法. 其他的部分都没有问题.

good luck to you

posted @ 2008-07-18 00:53 new 维生素C.net() 阅读(69) | 评论 (0)编辑