|
|
51CTO旗下网站
|
|
移步端
  • Apache Hadoop代码质量:生产VS高考

    让咱看一下PVS-Studio静态分析器警告,以查看测试错误并不比生产错误更严重这一事实的重大。现行的要害:Apache Hadoop。

    笔者:加米谷大数据 来源:当日第一| 2020-01-13 15:38

    为了获得高质量的生产代码,仅确保测试的最大覆盖范围还缺乏。毋庸讳言,良好之结果需要着重的品种代码和高考才能有效地协同工作。故此,高考必须与源代码一样受到重视。荣誉的统考是成功之严重性因素,因为他将遇到生产的衰退。让咱看一下PVS-Studio静态分析器警告,以查看测试错误并不比生产错误更严重这一事实的重大。现行的要害:Apache Hadoop。

    Apache Hadoop代码质量:生产VS高考

    关于该项目

    该署以前对大数量感兴趣的人数可能已经听说过Apache Hadoop品种或与之合作。概括,Hadoop是可以用作构建和利用大数量系统之根基的框架。

    Hadoop由四个第一模块组成;她们每个人都实施Big Dat $$ anonymous $$ nalytics系统所需的一定任务:

  • Hadoop合同。
  • MapReduce。
  • Hadoop分布式文件系统。
  • YARN。
  • 关于支票

    如文档中所示,PVS-Studio可以通过多种艺术集成到花色中:

  • 采用Maven硬件。
  • 采用Gradle硬件。
  • 采用Gradle IntellJ IDEA。
  • 直接行使分析仪。
  • Hadoop基于Maven构建系统;故此,检查没有其他障碍。

    在集成了文档中的脚本并编辑了一番pom.xml文件(依托项中有部分模块不可用)后,剖析起来了!

    剖析完成后,我选择了最有趣的警示,并注意到在生养代码和高考中,我具有相同数量之警示。普通,我不考虑测试中的分析器警告。但是,顶我将它们分开时,我一筹莫展不理会“高考”警告。我想:“为什么不看一下它们,因为测试中的错误也可能带来不利的结果。” 它们可能导致错误或一些测试,甚至导致杂乱。

    慎选最有趣的警示后,我将他分为以下几类:生产,高考和四个第一Hadoop模块。如今,我很喜欢对分析仪警告进行回顾。

    生产代码

    Hadoop科普

    V6033已经添加了具有相同键“ KDC_BIND_ADDRESS”的品种。MiniKdc.java(163),MiniKdc.java(162)

    Java

          
    1. 1个国有 类 MiniKdc {2  ....3 个体 静态 末了 Set < String >  
    2.  PROPERTIES  =  new  HashSet < String >();4  ....5 静态 {6  性质。 
    3. 补充(ORG_NAME);7  性质。补充(ORG_DOMAIN);8  性质。补充 
    4. (KDC_BIND_ADDRESS);9  性质。补充(KDC_BIND_ADDRESS); // <=10  性 
    5. 质量。加(KDC_PORT);11  性质。加(INSTANCE);12   ....13  }14  ....15} 

    HashSet检查项目时,a官方两次增加的值 是一番奇异广泛的缺点。其次个添加项将把忽视。我期望这种重复只是一场不必要的传奇。如果要补另一番值怎么办?

    MapReduce

    V6072找到两个相似之编码片段。也许这是一番错字, localFiles有道是使用变量代替 localArchives。

  • LocalDistributedCacheManager.java(183)。
  • LocalDistributedCacheManager.java(178)。
  • LocalDistributedCacheManager.java(176)。
  • LocalDistributedCacheManager.java(181)。
  • Java

          
    1. 1个国有 同步 无效 安装(JobConf  conf,JobID  jobId)抛出 IOException  
    2. {2  ....3 //采用本地化数据更新配置对象。4 如果(!localArchives。的 
    3. isEmpty()){5  conf。集(MRJobConfig。 
    4. CACHE_LOCALARCHIVES,StringUtils的6     。 
    5. arrayToString(localArchives。指定者(新 字符串 [ localArchives  //  
    6. <=7       。大大小小()])));8  }9 如果(!localFiles。的 
    7. isEmpty()){10  conf。集(MRJobConfig。 
    8. CACHE_LOCALFILES,StringUtils的11     。arrayToString(localFiles。指 
    9. 定者(新 字符串 [ localArchives    // <=12       。大大小小 
    10. ()])));13  }14  ....15} 

    V6072诊断程序有时会产生一些有趣的意识。此诊断的目的是检测由于复制粘贴和替换两个变量而导致的相同类型的编码片段。在这种情况下,少数变量甚至保持“有序”。

    地方的编码演示了这一点。在先后一个块中, localArchives增量用于第二个类似之组成部分 localFiles。如果您认真钻研此代码,而不是很快进行遍历,这通常在代码审阅时发生,这就是说您会注意到该片段,笔者忘记了替换该 localArchives增量。

    这种失态可能导致以下情况:

  • 假设我们有localArchives(大大小小= 4)和localFiles(大大小小= 2)。
  • 创造数组时 localFiles.toArray(new String[localArchives.size()]),说到底两个因素将为null(["pathToFile1", "pathToFile2", null, null])。
  • 下一场, org.apache.hadoop.util.StringUtils.arrayToString名将返回数组的字符串表示形式,其中最后的店名将显示为“ null”(“ pathToFile1,pathToFile2,null,null”)。
  • 整整这些都将进一步传递,上帝只掌握这种情况下会有什么样的检查。

    V6007分立式'children.size()> 0'前后为true。Queue.java(347)

    Java

          
    1. 1个boolean  isHierarchySameAs(Queue  newState){2  ....3 如果(儿女  
    2. ==  空 ||  儿女。大大小小()==  0){4   ....5  }6 否则 ,如果(儿女。大 
    3. 小()>  0)7  {8   ....9  }10  ....11} 

    出于要单独检查元素数是否为0,故此进一步检查children.size()> 0名将始终为true。

    HDFS

    V6001在'%'运算符的左手和右侧有相同的子表达式'this.bucketSize'。RollingWindow.java(79)。

    Java

          
    1. 1个 RollingWindow(int  windowLenMs,int  numBuckets){2  buckets  =  
    2.  new  Bucket [ numBuckets ];3  forint  i  =  0 ; i  <  numBuckets ;  
    3. i ++){4   buckets [ i ] =  new  Bucket();5   }6  其一。windowLenMs  
    4.  =  windowLenMs ;7  其一。bucketSize  =  windowLenMs  /  numBuckets  
    5. ;8  如果(此。bucketSize  % bucketSize  !=  0){      // <=9   抛出 
    6.  新的 IllegalArgumentException(10     “滚动窗口中的存储桶大小不是整 
    7. 数:windowLenMs =”11       +  windowLenMs  +  “ numBuckets =”“  + 
    8.   numBuckets);12   }13  } 

    YARN

    V6067两个或更多案例分支执行相同的借鉴。TimelineEntityV2Converter.java(386),TimelineEntityV2Converter.java(389)。

    Java

          
    1. 1个 集体 静态 ApplicationReport2  
    2. convertToApplicationReport(TimelineEntity  实体)3{4  ....5 如果 
    3. (指标 !=  null){6  long  vcoreSeconds  =  0 ;7  long   
    4. memorySeconds  =  0 ;8  long  preemptedVcoreSeconds  =  0 ;9  long 
    5.   preemptedMemorySeconds  =  0 ;1011  对于(TimelineMetric  指标: 
    6. 指标){12   开关(度量。的getId()){13   case   
    7. ApplicationMetricsConstants。APP_CPU_METRICS:14    vcoreSeconds  
    8.  =  getAverageValue(度量。的GetValues。()的值());15    休息  
    9. ;16   case  ApplicationMetricsConstants。APP_MEM_METRICS:17    
    10.  memorySeconds  = ....;18岁    休息 ;19   case  
    11.  ApplicationMetricsConstants。APP_MEM_PREEMPT_METRICS:20     
    12. preemptedVcoreSeconds  = ....;             // <=21    休息 ;22    
    13. case  ApplicationMetricsConstants。APP_CPU_PREEMPT_METRICS:23   
    14.   preemptedVcoreSeconds  = ....;             // <=24    休息 ;25  
    15.   默认值:26    //不应当发生27    休息 ;28    }29   }30   ....31 
    16.   }32  ....33} 

    相同的编码片段位于两个case分支中。大街小巷都是!在大部分情况下,这不是真实的错误,而只是考虑重构switch说话的由来。对于目前的状况,气象并非如此。重温的编码片段设置变量的值preemptedVcoreSeconds。如果仔细查看所有变量和常量的称谓,可能会得出结论,在这种情况下, if metric.getId() == APP_MEM_PREEMPT_METRICS必须为preemptedMemorySeconds增量设置 值,而不是 preemptedVcoreSeconds。在这方面,在switch说话之后,preemptedMemorySeconds名将始终保持0,而的值 preemptedVcoreSeconds可能不科学。

    V6046分立式错误。企望使用不同数量之公式项。不采取的底数:2. AbstractSchedulerPlanFollower.java(186)

    Java

          
    1. 1个@Override2市民 同步 无效 synchronizePlan(计划 精算,布尔  
    2. shouldReplan)3{4  ....5 尝试6  {7   
    3. setQueueEntitlement(planQueueName,....);8  }9 破获(YarnException  
    4.  e)10  {11  LOG。警告(“尝试为计划{{}确认保留大小时发生异常”,12 
    5.        currResId,13       planQueueName,14       e);15  }16  ....17} 

    planQueueName记录时不采取该 增量。在这种情况下,要么复制太多,要么格式字符串未完成。但是我仍然要责备旧的摄制粘贴,在少数情况下,名将他粘贴在脚上真是太好了。

    高考代码

    Hadoop科普

    V6072找到两个相似之编码片段。也许这是一番错字,有道是使用'allSecretsB'增量而不是'allSecretsA'。

    TestZKSignerSecretProvider.java(316),TestZKSignerSecretProvider.java(309),TestZKSignerSecretProvider.java(306),TestZKSignerSecretProvider.java(313)。

    Java

          
    1. 1个public  void  testMultiple(整数 先后)引发 独特 {2   ....3   
    2. currentSecretA  =  secretProviderA。getCurrentSecret();4   
    3. allSecretsA  =  secretProviderA。getAllSecrets();5  断言。 
    4. assertArrayEquals(secretA2,currentSecretA);6  断言。的 
    5. assertEquals(2,allSecretsA。长);     // <=7  断言。 
    6. assertArrayEquals(secretA2,allSecretsA [ 0 ]);8  断言。 
    7. assertArrayEquals(secretA1,allSecretsA [ 1 ]);910  currentSecretB   
    8. =  secretProviderB。getCurrentSecret();11  allSecretsB  =   
    9. secretProviderB。getAllSecrets();12  断言。 
    10. assertArrayEquals(secretA2,currentSecretB);13  断言。的 
    11. assertEquals(2,allSecretsA。长);    // <=14  断言。 
    12. assertArrayEquals(secretA2,allSecretsB [ 0 ]);15  断言。 
    13. assertArrayEquals(secretA1,allSecretsB [ 1 ]);16   ....17} 

    再次是V6072。精心察看变量allSecretsA和allSecretsB。

    V6043考虑检查“ for”运算符。迭代器的初始值和尾声值相同。TestTFile.java(235)。

    Java

          
    1. 1个人有 int  readPrepWithUnknownLength(环顾 表扫描仪,int   
    2. start,int  n)2  引发 IOException {3 对于(int  i  =  start ; i  <   
    3. start ; i ++){4  字符串 键 =  字符串。分立式(localFormatter,i);5   
    4. 字节 [] 读取 =  readKey(扫描仪);6  assertTrue(“键不等于”,阵列。 
    5. 等号(键。的getBytes(),读));7  尝试 {8   读取 =  读取值(环顾 
    6. 表);9   assertTrue(false);10   }11  抓(IOException  即){12   // 
    7. 有道是抛出异常13   }14  字符串 值 =  “值”  +  键;15  读取 =   
    8. readLongValue(探测器,值。的getBytes()。长);16  assertTrue(“n 
    9. 要相等的值”,阵列。等号(读,值。的getBytes()));17  扫描仪。提高 
    10. ();18岁  }19 回到(start  +  n);20} 

    前后是绿色的统考?=)。循环的组成部分,即测试本身的组成部分,名将永不会执行。这是出于以下事实:for说话中的初始计数器值和尾声计数器值相等 。结果,谱 i < start名将立即变为假,故而导致这种行为。我浏览了科考文件,下一场得出i < (start + n)必须在循环条件下编写的总结 。

    MapReduce

    V6007分立式'byteAm <0'前后为false。DataWriter.java(322)

    Java

          
    1. 个GenerateOutput  writeSegment(long  byteAm,OutputStream  out)2  
    2.  引发 IOException {3 long  headerLen  =  getHeaderLength();4  
    3. if(byteAm  <  headerLen){5  //没有足够的字节写头6  回到 新  
    4. GenerateOutput(0,0);7  }8 //调整标题长度9 byteAm-  =  headerLen  
    5. ;10 if(byteAm  <  0){   // <=11  byteAm  =  0 ;12  }13  ....14} 

    谱 byteAm < 0前后为假。为了弄清楚,让咱在地方的编码再瞅一遍。如果测试执行达到了操作的要求 byteAm -= headerLen,则意味着 byteAm >= headerLen。副此间开始,调减后,该 byteAm值将永不会为负。那就是咱们必须证明的。

    HDFS

    V6072找到两个相似之编码片段。也许这是一番错字, normalFile有道是使用变量代替 normalDir。TestWebHDFS.java(625),TestWebHDFS.java(615),TestWebHDFS.java(614),TestWebHDFS.java(624)

    Java

          
    1. 1个public  void  testWebHdfsErasureCodingFiles()引发 独特 {2  
    2.  ....3 末了 途径 normalDir  =  新 途径(“ / dir”);4 dfs。 
    3. mkdirs(normalDir);5 末了 途径 normalFile  =  新 途径 
    4. (normalDir,“ file.log ”);6  ....7 //逻辑块#18 时光filestatus  
    5.  expectedNormalDirStatus  =  DFS。getFileStatus(normalDir);9  
    6. FileStatus  actualNormalDirStatus  =  webHdfs。 
    7. getFileStatus(normalDir); // <=10 断言。的 
    8. assertEquals(expectedNormalDirStatus。isErasureCoded(),11    
    9.         actualNormalDirStatus。isErasureCoded());12  
    10. ContractTestUtils。assertNotErasureCoded(dfs,normalDir);13  
    11. assertTrue(normalDir  +  “应具有擦除编码中未设置”  +  
    12. ....);1415 //逻辑块#216 时光filestatus  expectedNormalFileStatus  
    13.  =  DFS。getFileStatus(normalFile);17 FileStatus   
    14. actualNormalFileStatus  =  webHdfs。getFileStatus(normalDir); // 
    15.  <=18岁 断言。的assertEquals(expectedNormalFileStatus。 
    16. isErasureCoded(),19           actualNormalFileStatus。 
    17. isErasureCoded());20 ContractTestUtils。 
    18. assertNotErasureCoded(dfs,normalFile);21 assertTrue(normalFile 
    19.   +  “应具有擦除编码中未设置”  + ....);22} 

    信不信由你,他又是V6072!只需跟随变量 normalDir和 normalFile。

    V6027穿过调用同一函数来初始化变量。可能是不对或未优化的编码。TestDFSAdmin.java(883),TestDFSAdmin.java(879)。

    Java

          
    1. 1个人人 void  verifyNodesAndCorruptBlocks(2  末了 整数 numDn,3  
    2.  final  int  numLiveDn,4  final  int  numCorruptBlocks,5  final   
    3. int  numCorruptECBlockGroups,6  末了的 DFSClient  客户端,7  说到底的  
    4. long  高高的PriorityLowRedundancyReplicatedBlocks,8  说到底的 Long  高高的 
    5. PriorityLowRedundancyECBlocks)9  引发 IOException10{11 / *初始化变 
    6. 量* /12  ....13 说到底的 字符串 ExpectedCorruptedECBlockGroupsStr  =  
    7.  String。分立式(14   “具有损坏的里间块的块组:%d”,15    
    8. numCorruptECBlockGroups);16 说到底的 字符串的  
    9. highestPriorityLowRedundancyReplicatedBlocksStr17   =  字符串。分立式 
    10. (18岁   “ \ t具有最高优先级的低冗余块”  +19     “要恢 
    11. 复:%d”,20   maximumPriorityLowRedundancyReplicatedBlocks);21 最 
    12. 此后的 字符串 highestPriorityLowRedundancyECBlocksStr  =  String。分立式 
    13. (22   “ \ t具有最高优先级的低冗余块”  +23     “要恢复:%d”,24   
    14.  maximumPriorityLowRedundancyReplicatedBlocks);25  ....26} 

    在这个局部中,highestPriorityLowRedundancyReplicatedBlocksStr和highestPriorityLowRedundancyECBlocksStr用相同的值初始化。普通应该是这样,但实际并非如此。增量的称谓又长又相似,故此复制粘贴的组成部分没有进行其它改变也就不足为奇了。为了消灭这个题目,在初始化highestPriorityLowRedundancyECBlocksStr增量时,笔者必须采取输入参数highestPriorityLowRedundancyECBlocks。另外,最有可能的是,她们仍然需要更正格式行。

    V6019检测不到代码。可能生存错误。TestReplaceDatanodeFailureReplication.java(222)。

    Java

          
    1. 1个人人 架空2verifyFileContent(....,SlowWriter [] slowwriters)引发 
    2.  IOException3{4 LOG。消息(“检验文件”);5 对(INT  我 =  0 ; 我 <  
    3.  slowwriters。长 ; 我++){6  LOG。消息(slowwriters [ 我 ]。文件路 
    4. 径 + ....);7  FSDataInputStream  in  =  null ;8  尝试 {9   in  =   
    5. fs。绽开(slowwriters [ 我 ]。文件路径);10   forint  j  =  0,x ;;  
    6. j ++){11    x  =  in官方。翻阅();12    如果((x)!=  - 1){13    
    7.   断言。assertEquals(j,x);14     } 其它 {15     回报 ;16     }17 
    8.     }18岁   } 说到底 {19   IOUtils。closeStream(in);20   }21  }22} 

    分析仪抱怨i++无法改变循环中的计数器。这意味着在for (int i = 0; i < slowwriters.length; i++) {....}循环中最多将实施一次迭代。让咱找出原因。在重要次迭代中,咱们将线程与回报的公文链接起来,以slowwriters[0]供进一步阅读。然后,咱们通过loop读取文件内容for (int j = 0, x;; j++)。

    如果我们读取了部分相关的情节,咱们会将读取的字节与j计数器的眼前值进行比较assertEquals(如果检查不成功,则测试失败)。

    如果文件检查成功,并且到达文件末尾(读取为-1),则该方法退出。

    故此,不论是在检查期间发生什么 slowwriters[0],都不会扮演检查后续元素。最有可能的是break,必须采取a代表return。

    YARN

    V6019检测不到代码。可能生存错误。TestNodeManager.java(176)

    Java

          
    1. 1个@高考2集体 无效 3testCreationOfNodeLabelsProviderService()引发 
    2.  InterruptedException {4 尝试 {5   ....6  } catch(独特 e){7  断言。 
    3. 失败(“破获到独特”);8  e。printStackTrace();9  }10} 

    在这种情况下,该 Assert.fail办法将暂停测试,并且在发生异常的情况下不会打印堆栈跟踪。如果有关捕获到的突出的信息在此间足够多,则最好删除打印堆栈跟踪的记录,以免造成混淆。如果需要打印,则只需交换它们。

    已发现众多类似之组成部分:

  • V6019检测不到代码。可能生存错误。TestResourceTrackerService.java(928)。
  • V6019检测不到代码。可能生存错误。TestResourceTrackerService.java(737)。
  • V6019检测不到代码。可能生存错误。TestResourceTrackerService.java(685)。
  • V6072找到两个相似之编码片段。也许这是一番错字, publicCache有道是使用变量代替 usercache。

          
    1. TestResourceLocalizationService.java(315),  
    2. TestResourceLocalizationService.java(309),  
    3. TestResourceLocalizationService.java(307),  
    4. TestResourceLocalizationService.java(313)  
    5. Java 
          
    1. 1个@高考2集体 无效 testDirectoryCleanupOnNewlyCreatedStateStore()3  
    2.  抛出 IOException,URISyntaxException4{5  ....6 //检验目录创建7 对于 
    3. (途径 p:localDirs){8  p  =  新 途径((新 URI(p。的 
    4. toString()))。的getPath());910  //逻辑块#111  途径 usercache 
    5.   =  新 途径(p,ContainerLocalizer。USERCACHE);12  检验(spylfs)。 
    6. 重命名(单位(usercache),其它(途径。类),其它()); // <=13  验 
    7. 证(spylfs)。mkdir(eq(usercache),....);1415  //逻辑块#216  路 
    8. 径 publicCache  =  新 途径(p,ContainerLocalizer。FILECACHE);17  验 
    9. 证(spylfs)。重命名(单位(usercache),其它(途径。类),其它 
    10. ()); // <=18岁  检验(spylfs)。 
    11. mkdir(eq(publicCache),....);19   ....20  }21  ....22} 

    说到底,再次是V6072 =)。用于查看可疑片段的总分: usercache 和publicCache。

    总结

    付出中编写了众多行代码。生产代码通常保持清洁,没有错误,症结和缺点(付出人员测试他们的编码,检查代码等)。在这方面,高考肯定不如。高考中的缺陷很容易隐藏在“浅绿色刻度”后面。正如您可能从今日的警示回顾中了解到的那样,浅绿色测试并不总是一项成功之检查。

    当下,顶检查Apache Hadoop代码库时,在生养代码和高考中都特别需要静态分析,而静态分析在开发中也起着重要作用。故此,如果您关心代码和高考质量,提议您着眼于静态分析。

    【编纂推荐】

    1. 手足,这种思路讲解HDFS你肯定没见过,很快入门Hadoop必备
    2. HDFS架构详解!会了这个,Hadoop还难理解吗?
    3. 客观建立Hadoop必发娱乐登录的7个步骤
    4. 副Hadoop到Spark和Flink,大数据处理框架十年激荡发展史
    5. Hadoop 3的首要优缺点
    【义务编辑: 未丽燕 TEL:(010)68476606】

    点赞 0
  • Hadoop  代码  品种
  • 分享:
    大家都在看
    猜你喜欢
  • 订阅专栏+更多

    Python使用场景实战手册

    Python使用场景实战手册

    Python使用场景实战手册
    共3章 | KaliArch

    115人口订阅学习

    一步到位玩儿透Ansible

    一步到位玩儿透Ansible

    Ansible
    共17章 | 骏马金龙1

    182人口订阅学习

    云架构师修炼手册

    云架构师修炼手册

    云架构师之必不可少技能
    共3章 | Allen在路上

    131人口订阅学习

    读 书 +更多

    硬件设计师考试全真模拟试题及解析

    该书是按照全国计算机技术与软件专业技能资格(水平)试验《硬件设计师考试大纲》的要求,参照《硬件设计师教程》及近年来考试问题编写的,...

    订阅51CTO邮刊

    点击这里查看样刊

    订阅51CTO邮刊

    51CTO劳务号

    51CTO官微

    &lt;form id="6c2bbb90"&gt;&lt;/form&gt;
  • &lt;ol id="60805378"&gt;&lt;/ol&gt;