2015年8月31日星期一

Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍 - shishanyuan

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍 - shishanyuan  阅读原文»

【注】该系列文章以及使用到安装包/测试数据 可以在《倾情大奉送--Spark入门实战系列》获取

1Spark Streaming简介

1.1 概述

Spark Streaming Spark核心API的一个扩展,可以实现高吞吐量的、具备容错机制的实时流数据的处理。支持从多种数据源获取数据,包括KafkFlumeTwitterZeroMQKinesis 以及TCP sockets,从数据源获取数据之后,可以使用诸如mapreducejoinwindow等高级函数进行复杂算法的处理。最后还可以将处理结果存储到文件系统,数据库和现场仪表盘。在“One Stack rule them all”的基础上,还可以使用Spark的其他子框架,如集群学习、图计算等,对流数据进行处理。

Spark Streaming处理的数据流图:

clip_image002

Spark的各个子框架,都是基于核心Spark的,Spark Streaming在内部的处理机制是,接收实时流的数据,并根据一定的时间间隔拆分成一批批的数据,然后通过Spark Engine处理这些批数据,最终得到处理后的一批批结果数据。

对应的批数据,在Spark内核对应一个RDD实例,因此,对应流数据的DStream可以看成是一组RDDs,即RDD的一个序列。通俗点理解的话,在流数据分成一批一批后,通过一个先进先出的队列,然后 Spark Engine从该队列中依次取出一个个批数据,把批数据封装成一个RDD,然后进行处理,这是一个典型的生产者消费者模型,对应的就有生产者消费者模型的问题,即如何协调生产速率和消费速率。

1.2 术语定义

l离散流(discretized stream)或DStream:这是Spark Streaming对内部持续的实时数据流的抽象描述,即我们处理的一个实时数据流,在Spark Streaming中对应于一个DStream 实例。

l批数据(batch data:这是化整为零的第一步,将实时流数据以时间片为单位进行分批,将流处理转化为时间片数据的批处理。随着持续时间的推移,这些处理结果就形成了对应的结果数据流了。

l时间片或批处理时间间隔( batch interval:这是人为地对流数据进行定量的标准,以时间片作为我们拆分流数据的依据。一个时间片的数据对应一个RDD实例。

l窗口长度(window length:一个窗口覆盖的流数据的时间长度。必须是批处理时间间隔的倍数,

Xcode7 无账号真机测试!! - 恣�垡�  阅读原文»

【摘要】Xcode 7如何免费真机调试iOS应用:运行Xcode后,点击菜单中的Preferences进入Accounts标签,这里选择添加Apple ID:在弹出的对话框中登入你的Apple ID,没有的话去注册一个就是了登录成功后会看到下面这样的信息:下面要做的是是生成开发证书,选中有Free的那项,然... 阅读全文

阅读更多内容

2015年8月29日星期六

Ubuntu下Tomcat初始配置 - chenxiaopang

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Ubuntu下Tomcat初始配置 - chenxiaopang  阅读原文»

1、下载tomcat安装包

从tomcat官方网站http://tomcat.apache.org下载安装包,然后解压到某个目录,比如: ~/opt/apache-tomcat-7.0.63
官方文档中建议不要使用各个Linux发行版中已经打好的安装包,因为各个发行版中的安装包将tomcat安装到不同的位置,所以建议不要使用源里的tomcat。
$tar xzvf apache-tomcat-7.0.63.tar.gz -C ~/opt

2、监听80端口

修改tomcat安装目录下conf目录下的server.xml
$cd ~/opt/apache-tomcat-7.0.63/conf
$vim server.xml
...
<Connector port="80"...>
...

3、增加用户

修改tomcat7安装目录下conf目录下的tomcat-users.xml文件
$cd ~/opt/apache-tomcat-7.0.63/conf
$vim tomcat-user.xml
...
<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="admin" password="1234" roles="admin-gui"/>
<user username="manager" password="1234" roles="manager-gui"/>
...

4、设置工作目录

Tomcat下的web程序默认目录为$TOMCAT_INSTALL_DIR/webapps,只要将自己的web程序目录放置到该目录下就可,但用户通常需要设置自己的工作目录。两种方法:

1)通过Context的docBase变量设置
$vim $TOMCAT_INSTALL_DIR/conf/Catalina/localhost/mywebapp.xml
<Context path="/mywebapp" docBase="~/working/project/program/webapps/mywebapp" reloadable="true"/>
注意:tomcat 5.5以后的版本,path变量可以不用设置,tomcat根据文件名来确定路径,例如:文件名为mywebapp.xml, 则路径为/mywebapp

2)软链接
$cd $TOMCAT_INSTALL_DIR/webapps
$ln -s ~/working/project/program/webapps/mywebapp mywebapp

5、安装Tomcat为随系统启动的服务

1) 在$TOMCAT_INSTALL_DIR/bin/setenv.sh脚本中设置JAVA_HOME环境变量
$vim $TOMCAT_INSTALL_DIR/bin/setenv.sh

#!/bin/sh

JAVA_HOME=/usr/lib/jvm/java-7-openjdk-i386

2)拷贝$TOMCAT_INSTALL_DIR/bin/catalina.sh到/etc/init.d目录下,并在脚本开头加入LSB的设置信息、tomcat安装位置环境变量设置:
$sudo cp catalina.sh /etc/init.d/tomcat
$sudo vim /etc/init.d/tomcat

### BEGIN INIT INFO
# Provides: apache-tomcat
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Run /etc/rc.local if it exist
### END INIT INFO

CATALINA_HOME="/home/cb/opt/apache-tomcat-7.0.63"
cd $CATALINA_HOME/bin

3)安装服务
$sudo update-rc.d -f tomcat defaults

4)启动/停止服务
$sudo service tomcat start
$sudo service tomcat stop

6、测试

$sudo service tomcat start

然后,打开浏览器,输入: http://localhost

以上在Ubuntu Kylin 14.04下测试通过。

=-=-=-=-=
Powered by Blogilo


本文链接:Ubuntu下Tomcat初始配置,转载请注明。

java中如何在Arraylist中实现冒泡排序的问题 - 临界  阅读原文»

    众所周知,冒泡排序法在一般数组中就3步,

1 if(a<b){
2 temp=a;
3 a=b;
4 b=temp;
5 }

然而,在集合中就不是简单的交换一下了,因为交换之后,必须保证新的值被重新设置到集合中去。那么变难了吗?实际上更简单了:

1 if(a<b){
2 workerlist.get(j).setSc(b);
3 workerlist.get(j+1).setSc(a);
4 }

原理还是交换,不过不需要媒介temple 了。

具体代码见下:

*********************工人类**********************

1 package com.xtkj.worker;
2 public class Worker{
3 int id;
4 String name;
5 int age;
6 double salary;
7
8 public Worker(){} //构造方法
9 public Worker(int id,String name, int age,double salary ) {
10 this.id = id;
11 this.name = name;
12 this.age = age;
13 this.salary = salary;
14 }
15 public String getName() {
16 return name;
17 }
18 public void setName(String name) {
19 this.name = name;
20 }
21 public int getId() {
22 return id;
23 }
24 public void setId(int id) {
25 this.id = id;
26 }
27 public double getSc() {
28 return salary;
29 }
30 public void setSc(double salary) {
31 this.salary = salary;
32 }
33 public int getAge() {
34 return age;
35 }
36 public void setAge(int age) {
37 this.age = age;
38 }
39
40 public Worker getNext(){
41 return this.getNext();
42 }
43
44 }

*******************方法类(这里只讲解冒泡排序)***************

1 package com.xtkj.worker;
2 import java.util.ArrayList;
3 import java.util.List;
4 import java.util.Scanner;
5 public class Method {
6 public static List<Worker> workerlist = new ArrayList<Worker>();
7 //按薪水由高到低排序
8 double temp;
9 double a=0;
10 double b=0;
11 void sort(){
12 System.out.println("按员工薪水从高到低排序结果为:");
13 for(int i=0;i<workerlist.size()-1;i++){
14 for(int j=0;j<workerlist.size()-1-i;j++){
阅读更多内容

2015年8月28日星期五

Gradle与Makefile构建工具的对比

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Gradle与Makefile构建工具的对比  阅读原文»

Gradle与Makefile构建工具的对比

随着Android Studio的普及,越来越多的Android开发者也要开始了解和学习Gradle这款强大的代码构建工具了。我们在学习和了解一项新事物的时候,最快速的方法往往是与已知的事物进行比较,对于熟悉Makefile编译机制的Linux程序员而言,认识和掌握Gradle最好的方法莫过于比较它们之间的区别了,本文不准备详细介绍Gradle的方方面面,而是希望通过与Makefile的对比帮助Gradle初学者更快速地理解Gradle的基础和原理。

Makefile是一种管理和编译 Linux C/C++ 项目的工具,而Gradle也是一种代码构建工具,只不过是针对Java语言的,它同样可以通过一些配置文件和脚本来完成代码的依赖、第三方库的引入、编译的自动化配置等功能。

首先说说Makefile,它是由一个个"规则"组成,每个"规则"都是由"目标"、"依赖"、"命令"构成, 一个最简单的Makefile如下所示:

  .PHONY: clean  all: hello  hello: hello.c      gcc -o hello hello.c  clean:      rm hello  

这里有三个"目标",分别是: "all","hello","clean"

当执行"make"命令时,编译器会默认查找目标"all" ,如果没有"all"则会查找Makefile文件的第一个目标。本示例中有"all"目标,它依赖"hello"目标,因此编译器会转而先构建"hello"目标,构建前, 编译器会先检测"hello"目标是否需要更新(通过判断"hello"文件与它所依赖的源文件"hello.c"的修改时间),如果需要,则执行后面的命令,而需要编译的源文件则是通过手动或者相关函数的方式添加到编译命令的参数中去的。

这就是makefile最核心的构建思想,通过一个个"目标"、"依赖"、"命令"来完成整个项目的关联和编译。那么,我们也根据这一思想来看看Gradle是怎么实现的。

1. Gradle是怎么识别源文件的 ?

Gradle是采取了一种"约定优于配置"的思想来完成这一点的,它通过"Plugin"来约定项目的目标和源文件的布局,例如: Java Plugin 定义的源文件布局如图所示:

wKioL1Xdnk2QXnWeAAEXQAiYhPc987.jpg

由该图可以很清楚地看到,Java Plugin 直接约定好了源文件的目录结构,在Gradle中,一般把这些源码目录的配置叫做"SourceSet",同理,Android提供的Android Plugin同样也定义了自己的源文件布局,还加入了如 jni, AndroidManifest.xml 等目录和文件。对于Gradle项目而言,需要在每个代码模块的"build.gradle"文件中定义使用哪一种Plugin, 例如:

  //普通的Java项目  apply plugin: 'java'  //Android Application  apply plugin: 'com.android.application'  //Android Library  apply plugin: 'com.android.library'  

2. Gradle是如何识别编译目标的 ?

在Gradle中,与Makefile的"目标"相对应的概念是"任务",即"task",Gradle的构建过程,就是执行一条一条"task"任务的过程, 同样,一个"task"也是可以依赖另一个"task"的,这样,通过这种依赖关系,就可以将整个项目中各个"task"链接到一起了。

与Makefile中手写目标的方式不同,Gradle将所有的"task"的定义全部交给Plugin来完成,由于每一种工程类型(Java项目、Android项目等),其构建过程都是大同小异的,因此为每一种类型的项目定义好了一种通用的Plugin,以后同类型的项目就可以直接使用该Plugin了,非常的灵活和方便。

当我们在项目中执行"gradle build"命令时,可以看到该项目使用的Plugin具体定义了哪些"task",例如一个典型的Java Plugin定义的"task"如下所示:

  :compileJava  :processResources  :classes  :jar  :assemble  :compileTestJava  :processTestResources  :testClasses  :test  :check  :build  

当然,虽然同是Android类型的工程,但不同的项目毕竟还是有配置上的差异,因此,Gradle的Plugin中也可以定义和导出一些特定的"元素"用于传递用户自定义的配置信息,例如: Google提供的"com.android.application" Plugin就定义了一个"android"元素,开发者可以在build.gradle中配置该元素的细节,比如定义一些: "项目的ID"、"sdk的版本"、"是否混淆"等等,例如:

  android {      compileSdkVersion 21      buildToolsVersion "21.1.1"      defaultConfig {          applicationId "com.jhuster.test"          minSdkVersion 15          targetSdkVersion 21          versionCode 1          versionName "1.0.0"       }  }  

3. Gradle命令怎么用 ?

gradle命令与make命令类似,都是用来执行编译/清理任务的,make命令默认查找当前目录下的Makefile文件,并且开始构建命令参数中所指定的"目标",例如:

  $make all  $make clean  

同样,gradle命令也是类似的用法,例如:

  $gradle build        //构建和打包整个项目  $gradle clean        //清除之前的构建  $gradle test         //执行测试  $gradle compileJava  //编译java  

4. Gradle是如何引入第三方库的 ?

对于Makefile而言,通常需要将第三方库的源码下载下来,编译为库后,放入到工程目录下,然后修改Makefile文件,在gcc/g++的编译链接参数中引用该第三方库的,例如:

  hello: hello.c      gcc -o hello hello.c -L/libs/foo.a  

而Gradle则是通过build.grade文件中的dependencies来配置的,例如:

  dependencies {      compile files('libs/foo.jar')  //以jar的方式引用      compile project(':foo')         //以library工程源码的方式引用  }  

另外,Gradle还支持类似Ubuntu软件源仓库的方式来引用第三方库,开发者可以将自己的第三方库上传到一些支持Gradle的中心仓库中,这样,其他人就可以通过配置build.gradle直接完成对第三方库的引用了,代码构建的时候Gradle会自动完成第三方库的下载和链接。比较常用的两个个中心仓库: jcenter,mavenCentral。

例如: 我们引用jcenter仓库的okhttp库,则build.gradle配置如下:

  allprojects {      repositories {          jcenter()      }  }  dependencies {      compile 'com.squareup.okhttp:okhttp:2.4.0'  }  

5. 小结

Gradle真的很强大很灵活,它将最核心的构建规都则交给了Plugin来完成,这样,轻松实现了构建过程的通用性,开发者只需要关注业务逻辑,以及少许的配置即可完成自动化编译和部署的过程,相比于Linux手写makefile要方便很多。好了,关于Gradle和Makefile的简单对比就介绍到这里了,希望对Gradle的初学者有所帮助,有任何疑问或者建议欢迎留言或者来信lujun.hust@gmail.com交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。

本文出自 "对影成三人" 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/1688586

每日博报 精彩不止一点

阅读更多内容

2015年8月27日星期四

深入理解Windows X64调试 - _懒人

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
深入理解Windows X64调试 - _懒人  阅读原文»

随着64位操作系统的普及,都开始大力进军x64,X64下的调试机制也发生了改变,与x86相比,添加了许多自己的新特性,之前学习了Windows x64的调试机制,这里本着“拿来主义”的原则与大家分享。

本文属于译文,英文原文链接:http://www.codemachine.com/article_x64deepdive.html

翻译原文地址:深入Windows X64 调试

在正式开始这篇译文之前,译者先定义下面两个关于栈帧的翻译:

  • frame pointer:栈帧寄存器、栈帧指针,在X86平台上,是EBP所指的位置
  • stack pointer:栈顶寄存器、栈顶指针,在X86平台上,是ESP所指的位置

这个教程讨论一些在 X64 CPU 上代码执行的要点,如:编译器优化、异常处理、参数传递和参数恢复,并且介绍这几个topic之间的关联。我们会涉及与上述topic相关的一些重要的调试命令,并且提供必要的背景知识去理解这些命令的输出。同时,也会重点介绍X64平台的调试与X86平台的不同,以及这些不同对调试的影响。最后,我们会活学活用,利用上面介绍的知识来展示如何将这些知识应用于X64平台的基于寄存器存储的参数恢复上,当然,这也是X64平台上调试的难点。

0x00 编译器优化

这一节主要讨论影响X64 code生成的编译器优化,首先从X64寄存器开始,然后,介绍优化细节,如:函数内联处理(function in-lining),消除尾部调用(tail call elimination), 栈帧指针优化(frame pointer optimization)和基于栈顶指针的局部变量访问(stack pointer based local variable access)。

  • 寄存器的变化

X64平台上的所有寄存器,除了段寄存器和EFlags寄存器,都是64位的,这就意味着在x64平台上所有内存的操作都是按64位宽度进行的。同样,X64指令有能力一次性处理64位的地址和数据。增加了8个新的寄存器,如: r8~r15,与其他的使用字母命名的寄存器不同,这些寄存器都是使用数字命名。下面的调试命令输出了 X64 平台上寄存器的信息:

1: kd> r
rax=fffffa60005f1b70 rbx=fffffa60017161b0 rcx=
000000000000007f rdx=0000000000000008 rsi=fffffa60017161d0 rdi=0000000000000000 rip=fffff80001ab7350 rsp=fffffa60005f1a68 rbp=fffffa60005f1c30 r8=0000000080050033 r9=00000000000006f8 r10=fffff80001b1876c r11=0000000000000000 r12=000000000000007b r13=0000000000000002 r14=0000000000000006 r15=0000000000000004 iopl=0 nv up ei ng nz na pe nc cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000282 nt!KeBugCheckEx:
fffff800`
01ab7350 48894c2408 mov qword ptr [rsp+8],rcx ss:0018:fffffa60`005f1a70=000000000000007f

相比较X86平台,一些寄存器的用法已经发生变化,这些变化可以按如下分组:

  1. 不可变寄存器是那些在函数调用过程中,值被保存起来的寄存器。X64平台拥有一个扩展的不可变寄存器集合,在这个集合中,以前x86平台下原有的不可变寄存器也包含在内,新增的寄存器是从R12到R15,这些寄存器对于函数参数的恢复很重要。
  2. Fastcall寄存器用于传递函数参数。Fastcall是X64平台上默认的调用约定,前4个参数通过RCX, RDX, R8, R9传递。
  3. RBP不再用作栈帧寄存器。现在RBP和RBX,RCX一样都是通用寄存器,调试前不再使用RBP来回溯调用栈。
  4. 在X86 CPU中,FS段寄存器用于指向线程环境块(TEB)和处理器控制区(Processor Control Region, KPCR),但是,在X64上,GS段寄存器在用户态是指向TEB,在内核态是指向KPCR。然而,当运行WOW64程序中,FS 寄存器仍然指向32位的TEB。

在X64平台上,trap frame的数据结构(nt!_KTRAP_FRAME)中不包含不可变寄存器的合法内容。如果X64函数会使用到这些不可变寄存器,那么,指令的序言部分会保存不可变寄存器的值。这样,调试器能够一直从栈中取到这些不可变寄存器原先的值,而不是从trap frame中去取。在X64内核模式调试状态下,`.trap`命令的输出会打印一个NOTE,用于告诉用户所有从trap frame中取出的寄存器信息可能不准确,如下所示:

1: kd> kv
Child-SP RetAddr : Args to Child .
.
.
nt!KiDoubleFaultAbort+0xb8 (TrapFrame @ fffffa60`
005f1bb0) .
.
.

1: kd> .trap fffffa60`005f1bb0
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed
or incorrect
  • 函数内联处理(Function in-lining)

如果满足一定的规则以后,X64编译器会执行内联函数的扩展,这样会将所有内联函数的调用部分用函数体来替换。内联函数的优点是避免函数调用过程中的栈帧创建以及函数退出时的栈平衡,缺点是由于指令的重复对导致可执行程序的大小增大不少,同时,也会导致cache未命中和page fault的增加。内联函数同样也会影响调试,因为当用户尝试在内联函数上设置断点时,调试器是不能找到对应的符号的。源码级别的内联可以通过编译器的/Ob flag 进行控制,并且可以通过__declspec(noinline)禁止一个函数的内联过程。图1显示函数2和函数3被内联到函数1的过程。

Figure 1 : Function In-lining

  • 消除尾部调用(Tail Call Elimination)

X64编译器可以使用jump指令替换函数体内最后的call指令,通过这种方式来优化函数的调用过程。这种方法可以避免被调函数的栈帧创建,调用函数与被调函数共享相同的栈帧,并且,被调函数可以直接返回到自己爷爷级别的调用函数,这种优化在调用函数与被调函数拥有相同参数的情况下格外有用,因为如果相应的参数已经被放在指定的寄存器中,并且没有改变,那么,它们就不用被重新加载。图2显示了TCE,我们在函数1的最后调用函数4:

Figure 2 : Tail Call Elimination

  • 栈帧指针省略(Frame Pointer Omission, FPO)

在X86平台下,EBP寄存器用于访问栈上的参数与局部变量,而在X64平台下,RBP寄存器不再使用充当同样的作用。取而代之的是,在X64环境下,使用RSP作为栈帧寄存器和栈顶寄存器,具体是如何使用的,我们会在后续的章节中做详细的叙述。(译者注:请区分X86中的FPO与X64中的FPO,有很多相似的地方,也有不同之处。关于 X86上的FPO,请参考《软件调试》中关于栈的描述)所以,在X64环境下,RBP寄存器已经不再担当栈帧寄存器,而是作为一般的通用寄存器使用。但是,有一个例外情况,当使用alloca()动态地在栈上分配空间的时候,这时,会和X86环境一样,使用RBP作为栈帧寄存器。 下面的汇编代码片段展示了X86环境下的KERNELBASE!Sleep函数,可以看到EBP寄存器被用作栈帧寄存器。当调用SleepEx()函数的时候,参数被压到栈上,然后,使用call指令调用SleepEx()。

0:009> uf KERNELBASE!Sleep KERNELBASE!Sleep:
75ed3511 8bff
mov edi,edi
75ed3513
55 push ebp
75ed3514 8bec
mov ebp,esp
75ed3516 6a00
push 0
75ed3518 ff7508
push dword ptr [ebp+8]
75ed351b e8cbf6ffff
call KERNELBASE!SleepEx (75ed2beb)
75ed3520 5d
pop ebp 75ed3521 c20400 ret 4.

下面的代码片段展示的是X64环境下相同的函数,与X86的code比起来有明显的不同。X64版本的看起来非常紧凑,主要是由于不需要保存、恢复RBP寄存器。

0:000> uf KERNE
剑指Offer面试题:12.在O(1)时间删除链表结点 - Edison Chou  阅读原文»

一、题目:在O(1)时间删除链表结点

题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

  原文采用的是C/C++,这里采用C#,节点定义如下:

public class Node<T>
{
// 数据域
public T Item { get; set; }
// 指针域
public Node<T> Next { get; set; }

public Node()
{
}

public Node(T item)
{
this.Item = item;
}
}

  要实现的DeleteNode方法定义如下:

public static void DeleteNode(Node<int> headNode, Node<int> deleteNode)
{
}

二、解题思路

2.1 常规思路

  在单向链表中删除一个结点,最常规的做法无疑是从链表的头结点开始,顺序遍历查找要删除的结点,并在链表中删除该结点。这种思路由于需要顺序查找,时间复杂度自然就是O(n)

2.2 正确思路

  是不是一定需要得到被删除的结点的前一个结点呢?答案是否定的。

  我们可以很方便地得到要删除的结点的一下结点。因此,我们可以把下一个结点的内容复制到需要删除的结点上覆盖原有的内容,再把下一个结点删除,就相当于把当前需要删除的结点删除了

  但是,还有两个特殊情况需要进行考虑:

  (1)如果要删除的结点位于链表的尾部,那么它就没有下一个结点:

  此时我们仍然从链表的头结点开始,顺序遍历得到该结点的前序结点,并完成删除操作,这仍然属于O(n)时间的操作。

  (2)如果链表中只有一个结点,而我们又要删除链表的头结点(也是尾结点):

  此时我们在删除结点之后,还需要把链表的头结点设置为NULL。

  最后,通过综合最坏情况(尾节点需要顺序查找,1次)和最好情况(n-1次),因此平均时间复杂度为:

  需要注意的是:受到O(1)时间的限制,我们不得不把确保结点在链表中的责任推给了函数DeleteNode的调用者

三、解决问题

3.1 代码实现

public static void DeleteNode(Node<int> headNode, Node<int> deleteNode)
{
if (headNode == null || deleteNode == null)
{
return;
}

if (deleteNode.Next != null) // 链表有多个节点,要删除的不是尾节点:O(1)时间
{
Node
<int> tempNode = deleteNode.Next;
deleteNode.Item
= tempNode.Item;
deleteNode.Next
= tempNode.Next;

tempNode
= null;
}
else if (headNode == deleteNode) // 链表只有一个结点,删除头结点(也是尾结点):O(1)时间
{
deleteNode
= null;
headNode
= null;
}
else // 链表有多个节点,要删除的是尾节点:O(n)时间
{
Node
<int> tempNode = headNode;
while(tempNode.Next != deleteNode)
{
tempNode
= tempNode.Next;
}

tempNode.Next
= null;
deleteNode
= null;
}
}

3.2 单元测试

  (1)封装返回结果

  该方法作为单元测试的对比方法,主要用来对比实际值与期望值是否一致:

public static string GetPrintNodes(Node<int> headNode)
{
if (headNode == null)
{
return string.Empty;
}

StringBuilder sbNodes
= new StringBuilder();
while(headNode != null)
{
sbNodes.Append(headNode.Item);
headNode
= headNode.Next;
}

return sbNodes.ToString();
}

  (2)测试用例

// 链表中有多个结点,删除中间的结点
[TestMethod]
public void DeleteNodeTest1()
{
Node
<int> head1 = new Node<int>(1);
Node
<int> head2 = new Node<int>(2);
Node
<int> head3 = new Node<int>(3);
Node
<int> head4 = new Node<int>(4);
Node
<int> head5 = new Node<int>(5);

head1.Next
= head2;
head2.Next
= head3;
head3.Next
= head

阅读更多内容

2015年8月25日星期二

一小时学会用Python Socket 开发可并发的FTP服务器!!

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
一小时学会用Python Socket 开发可并发的FTP服务器!!  阅读原文»

一小时学会用Python Socket 开发可并发的FTP服务器!!

socket是什么

什么是socket所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。说白了就是一种通信机制。它类似于银行,电信啊这些部分的电话客服部门。你打电话的时候,那边会分配置一个人回答你的问题,客服部门就相当于socket的服务器端了,你这边呢就相当于客户端了,在和你通话结束前,如果有人在想找和你通话的那个说话,是不可能的,因为你在和他通信,当然客服部门的电话交换机也不会重复分配。我们天天用的http\smtp\ftp等网络协议都是基于socket的上层实现,无论使用何种网络协议,最本质上都是在进行数据的接收和发送,只不过发送的数据类型和内容不同罢了,"发送"和"接收"这两个动作就是socket处理数据的主要方式。

socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",都可以用"打开open> 读写write/read> 关闭close"模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/IO、打开、关闭),pythonsocket模块是直接调用的unixsocket库,接下来我们一起来看下,如何在python下实现socket

使用socket时需要指定Socket Family(地址簇),包括以下几种:

socket.AF_UNIX 只能够用于单一的Unix系统进程间通信

socket.AF_INET 用于主机之间的网络通信

socket.AF_INET6 IPv6通信

若想实现主机之间的通信,我们就得使用socket.AF_INET

确认地址簇后,还需要指定socket 数据类型

socket.SOCK_STREAM 流式socket, for TCP

socket.SOCK_DGRAM 数据报式socket, for UDP

socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMPIGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。

socket.SOCK_SEQPACKET 可靠的连续数据包服务

我们主要用的一般是SOCK_STREAM (for TCP)SOCK_DGRAMfor UDP.

进行socket调用时可能会用到的函数:

s = socket(family,type[,protocal]) 使用给定的地址族、套接字类型、协议编号(默认为0)来创建套接字。

套接字的实例具有以下方法:

  1. s.bind(address)将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

  2. s.listen(backlog) 开始监听传入连接。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。

  3. s.connect(address) 连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接同一台机器上的服务器,可以将hostname设为'localhost'。如果连接出错,返回socket.error错误。

  4. s.connect_ex(adddress) 功能与connect(address)相同,但是成功返回0,失败返回errno的值。

  5. s.accept()接受连接并返回(conn,address,其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

  6. s.close()关闭套接字。

  7. s.fileno()返回套接字的文件描述符。

  8. s.getpeername()返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

  9. s.getsockname()返回套接字自己的地址。通常是一个元组(ipaddr,port)

  10. s.getsockopt(level,optname[.buflen]) 返回套接字选项的值。

  11. s.gettimeout()返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None

  12. s.recv(bufsize[,flag]) 接受套接字的数据。数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。

  13. s.recvfrom(bufsize[.flag]) recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

  14. s.send(string[,flag]) string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

  15. s.sendall(string[,flag]) string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

  16. s.sendto(string[,flag],address) 将数据发送到套接字,address是形式为(ipaddrport)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

  17. s.setblocking(flag) 如果flag0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。

  18. s.setsockopt(level,optname,value) 设置给定套接字选项的值。

  19. s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())普通的非套接字实例的函数

  20. getdefaulttimeout()返回默认的套接字超时时间(以秒为单位)。None表示不设置任何超时时间。

  21. gethostbyname(hostname) 将主机名?p>阅读更多内容

Oracle GoldenGate 二、配置和使用 - 堅持╅信念★

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Oracle GoldenGate 二、配置和使用 - �猿蜘樾拍睢�  阅读原文»

配置和使用GoldenGate的步骤

  • 1 在源端和目标端配置数据库支持GoldenGate
  • 2 在源端和目标端创建和配置GoldenGate实例
  • 3 在源端创建和配置主抽取进程(Primary Extract)
  • 4 在源端创建和配置Data Pump进程(Secondly Extract)
  • 5 在目标端创建和配置Replicat进程

1 配置数据库支持GoldenGate

1.1 OGG用户和权限分配

  GoldenGate需要从在线日子或归档日志抽取捕获系统的变更数据信息,这些信息可能来源于业务用户,可能来源于系统用户,为了使GoldenGate能够抽取这些数据应为GoldenGate创建独立的用户和分配必要的权限以满足系统运行需求,这些权限包括读取业务用户表数据的权限、读取系统表的权限、执行某个系统包的权限等,以下脚步创建GoldenGate用户ogg_owner(源用户)、ogg_trg(目标用户)和GoldenGate角色ogg_role:

[oracle@sywu ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.3.0 Production on Fri Aug 21 14:11:04 2015

Copyright (c) 1982, 2011, Oracle. All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

SYS@sydb>create tablespace tbs01
datafile '+oradata'
size 10m
autoextend on
uniform size 2m
/
create user ogg_owner identified by ogg_owner default tablespace tbs01 quota unlimited on tbs01
/
create user ogg_trg identified by ogg_trg default tablespace tbs01 quota unlimited on tbs01
/
create role ogg_role
/

为易管理和维护统一将权限赋予角色ogg_role:

grant
CREATE SESSION,
ALTER SESSION,
ALTER SYSTEM,
RESOURCE,
SELECT ANY DICTIONARY,
FLASHBACK ANY TABLE,
SELECT ANY TABLE,
SELECT ANY TRANSACTION,
insert any table,
update any table,
drop any table,
CREATE TABLE
to ogg_role;

grant SELECT on dba_clusters to ogg_role;
grant SELECT on V_$DATABASE to ogg_role;Android Volley源码分析 - 希尔瓦娜斯女神  阅读原文»

今天来顺手分析一下谷歌的volley http通信框架。首先从github上 下载volley的源码,

然后新建你自己的工程以后 选择import module 然后选择volley。 最后还需要更改1个

配置文件

就是我选中的那句话。记得要加。不然会报错。把volley作为一个module 在你的项目中引用的原因是,因为我们要分析源码,需要测试我们心中所想。所以这么做是最方便的。

就相当于eclipse里面的工程依赖。

有关于volley 如何使用的教程 我就不在这写了,请自行谷歌,我们直接看源码。

1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.volley.toolbox;
18
19 import android.content.Context;
20 import android.content.pm.PackageInfo;
21 import android.content.pm.PackageManager.NameNotFoundException;
22 import android.net.http.AndroidHttpClient;
23 import android.os.Build;
24 import android.util.Log;
25
26 import com.android.volley.Network;
27 import com.android.volley.RequestQueue;
28
29 import java.io.File;
30
31 public class Volley {
32
33 /**
34 * Default on-disk cache directory.
35 */
36 private static final String DEFAULT_CACHE_DIR = "volley";
37
38 /**
39 * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
40 *
41 * @param context A {@link Context} to use for creating the cache dir.
42 * @param stack An {@link HttpStack} to use for the network, or null for default.
43 * @return A started {@link RequestQueue} instance.
44 */
45 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
46 File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
47 String userAgent = "volley/0";
48 try {
49 String packageName = context.getPackageName();
50 PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
51 userAgent = packageName + "/" + info.versionCode;
52 } catch (NameNotFoundException e) {
53 }
54
55 /**
56 * 注意android 2.3之前一般用httpcilent进行网络交互 2.3包括2.3以后才使用HttpURLConnection
57 * 这里面 实际上hurlstack就是 HttpURLConnection的一个变种
58 */
59 if (stack == null) {
60 if (Build.VERSION.SDK_INT >= 9) {
61
62 stack = new HurlStack();
63 } else {
64 // Prior to Gingerbread, HttpUrlConnection was unreliable.
65 // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
66 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
67 }
68阅读更多内容

2015年8月23日星期日

Windows 10企业批量部署实战之Logs日志存放

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Windows 10企业批量部署实战之Logs日志存放  阅读原文»

Windows 10企业批量部署实战之Logs日志存放

在使用MDT部署操作系统的时候,很多时候会出现报错情况,为了方便我们的排错操作或者检测客户端是否完整部署等,Logs日志的收集是必不可少的,本章就如何设置客户端在部署过程中将日志存放到远程服务器端的操作步骤,所有操作均为服务器端设置。

1、首先我们需要在MDT服务器端新建共享文件夹,并设置该文件夹对Everyone用户可读可写:

2、设置共享后网络路径显示如下:

3、选择MDT Deployment share控制台右键属性:

4、在rules值中添加Slshare、SLshareDynamicLogging值分别指定日志文件夹位置并设置以计算机名存放:

5、有关Logs日志的设置基本完成,单击确定完成设置。

生产环境中建议添加该参数值,方便我们在部署过程中出现错误的排错操作,或者在客户端本地收集\_SMSTaskSequence\Logs\smsts.log日志排错。

本文出自 "" 博客,请务必保留此出处http://wenzhongxiang.blog.51cto.com/6370734/1686620

每日博报 精彩不止一点

Powershell Module for Netapp Data Ontap  阅读原文»

Powershell Module for Netapp Data Ontap

今天无意中看见Netapp提供Data Ontap 的powershell 模块,豆子兴致勃勃的下载试了试。

下载链接

http://mysupport.netapp.com/NOW/download/tools/powershell_toolkit/

具体安装module的过程不说了,参考

http://community.netapp.com/t5/Virtualization-and-Cloud-Articles-and-Resources/Making-The-Most-Of-Data-ONTAP-PowerShell-Toolkit/ta-p/87234

花了1个小时学习了基本命令,写了一个简单的脚本测试效果

基本功能是连接到两个filer上,读取上面的volume,如果volume的磁盘使用超过90%,那么给我发个警告信,并列出上面所有的snapshot快照。

  $syd01=Connect-NaController syd01  $syd02=Connect-NaController syd02  $filers=$syd01,$syd02  $logtime=Get-Date -Format "MM-dd-yyyy_hh-mm-ss"  $path="C:\temp\logs\$logtime.txt"  New-Item -Path $path -ItemType file -Force  foreach($filer in $filers){  Connect-NaController $filer  $a=Get-NaVol | Where-Object{$_.used -ge 90}  foreach($b in $a){  $b | ft >> $path  $b| Get-NaSnapshot  |sort created |ft >> $path  }  }  $from = "sender@abc.com"  $to = "test@abc.com"  $smtp = "smtp.office365.com"  $sub = "Volume over 90%"  $body="This is the warning message for volume usage over 90%"  $secpasswd = ConvertTo-SecureString "PasswordXXX" -AsPlainText -Force  $mycreds = New-Object System.Management.Automation.PSCredential ($from, $secpasswd)  if ((get-content $path).length -gt 0){  Send-MailMessage -To $to -From $from -Subject $sub -Body $body -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAsHtml -UseSsl -port 587 -Attachments $path  }  

执行脚本,1分钟后收到邮件,打开看看,附件里面是快照的细节。

可以看见snap protect自动产生的备份文件。这个和我从OnCommand System的图像界面看见的效果是一样的。

wKiom1XVfG-QKrnsAATIn5rzbZ4796.jpg

对比一下我之前的使用方式

相比SSH连接到filer,然后执行命令,powershell明显简单好使的多,如果有其他模块的使用经验,基本上1个小时就能轻松上手,这个是因为powershell 自己固定的命名方式和使用习惯,如果开发者严格遵从高级功能的模板和命名习惯,用户使用起来没有任何别扭的感觉。

相比OnCommnd的图形界面,GUI和浏览器,Java的兼容性一直有点问题,有时候打开界面又慢又显示不出东西;powershell的速度快速的多,如果需要配置多个filer和volume,效果要好很多。一些删除的命令也很贴心的提供了-whatif,这样可以避免误操作。

本文出自 "麻婆豆腐" 博客,请务必保留此出处http://beanxyz.blog.51cto.com/5570417/1686459

每日博报 精彩不止一点

阅读更多内容

java spring 邮件发送 - 每日懂一点

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
java spring 邮件发送 - 每日懂一点  阅读原文»

  开发中经常会遇到发送邮件进行用户验证,或者其它推送信息的情况,本文基于spring,完成邮件的发送,主要支持普通文本邮件的发送,html文本邮件的发送,带附件的邮件发送,没有实现群发、多个附件发送等需求。如果需要可以参照如下源代码进行修改完成。
  1. POM文件配置
    1 <dependencies>
    2 <dependency>
    3 <groupId>org.springframework</groupId>
    4 <artifactId>spring-context</artifactId>
    5 <version>4.1.6.RELEASE</version>
    6 </dependency>
    7 <dependency>
    8 <groupId>org.springframework</groupId>
    9 <artifactId>spring-context-support</artifactId>
    10 <version>4.1.6.RELEASE</version>
    11 </dependency>
    12 <dependency>
    13 <groupId>javax.mail</groupId>
    14 <artifactId>mail</artifactId>
    15 <version>1.4.7</version>
    16 </dependency>
    17 </dependencies>
  2. spring 配置
    1 <!-- Production implementation of the JavaMailSender interface, supporting
    2 both JavaMail MimeMessages and Spring SimpleMailMessages -->
    3 <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    4 <property name="host" value="smtp.gmail.com" />
    5 <property name="port" value="587" />
    6 <property name="username" value="<!-- Provide your Gmail ID -->" />
    7 <property name="password" value="<!-- Provide your Gmail Password -->" />
    8
    9 <!-- The name of the property, following JavaBean naming conventions -->
    10 <property name="javaMailProperties">
    11 <props>
    12 <prop key="mail.transport.protocol">smtp</prop>
    13 <prop key="mail.smtp.auth">true</prop>
    14 <prop key="mail.smtp.starttls.enable">true</prop>
    15 <prop key="mail.debug">true</prop>
    16 </props>
    数据库的读读事务也会产生死锁 - 桦仔  阅读原文»

    数据库的读读事务也会产生死锁

    前段时间有朋友问:SQL Server的AlwaysOn的辅助数据库默认会使用行版本快照控制来消除数据库上的读写事务阻塞和死锁问题

    即使用户显式为查询设置了其他事务隔离级别,所有锁提示(Lock Hint)都会被忽略。

    为了保证数据同步的完整性,AlwaysOn规定来自数据同步(redo 日志)所做的写操作永远不会被选为死锁牺牲品,无论该写操作的代价多小。

    AlwaysOn的做法其实很好理解,数据库中的事务操作无非就四种

    1、读读

    2、读写

    3、写读

    4、写写

    第二种、第三种和第四种造成阻塞和死锁很容易理解,读事务得到的锁资源不释放就有可能造成写事务失败或者写事务得到的锁资源不释放就有可能造成读事务

    但是第一种读读事务也会造成死锁吗?

    我这里做一个实验

    1、先确保数据库没有使用任何快照隔离级别

    USE [tt1]
    DBCC USEROPTIONS

    2、脚本1

    USE [tt1];

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRAN
    SELECT * FROM [dbo].[Table_1] WITH (ROWLOCK) WHERE [q]=88

    3、脚本2

    USE [tt1];

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRAN

    SELECT * FROM [dbo].[Storage] WITH (TABLOCKX)

    SELECT * FROM [dbo].[Table_1] WHERE [q]=7

    4、脚本3

    USE [tt1];

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRAN
    SELECT * FROM [dbo].[Table_1] WITH (ROWLOCK) WHERE [q]=88

    5、脚本4

    USE [tt1];

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRAN
    SELECT * FROM [dbo].[Table_1] WITH (ROWLOCK)

    6、在多个查询窗口(session)里执行上面的脚本

    7、打开跟踪标记

    DBCC TRACEON (1204, 1222, -1);
    DBCC tracestatus

    8、过一会儿就会看到其中一个session 59已经作为死锁牺牲品

    9、在errorlog里已经看到spid为4的死锁监视器(LOCK MONITOR)已经监测到死锁的存在

    EXEC xp_readerrorlog 0,1,NULL,NULL,'2015-08-06','2015-10-10','DESC'


    总结

    多人都不了解为什么SELECT语句也会产生死锁,其实SELECT语句一般在RC隔离级别下很少会发送死锁,只是用户在日常开发中会使用了一些不恰当的锁提示(Lock Hint)或者提升了事务隔离级别而导致

    日常开发中我们都要注意不要滥用锁提示(Lock Hint),根据实际情况进行判断,该提升事务隔离级别就提升事务隔离级别,以免造成不必要的死锁。

    如有不对的地方,欢迎大家拍砖o(∩_∩)o


    本文链接:数据库的读读事务也会产生死锁,转载请注明。

    阅读更多内容