首页 文章 精选 留言 我的

精选列表

搜索[源码学习],共10000篇文章
优秀的个人博客,低调大师

LevelDB源码分析-sstable的Block

sstable中的Block(table/block.h table/block.cc table/block_builder.h table/block_builder.cc) sstable中的block由Block类封装并由BlockBuilder类构建。 block的结构为: entry1 | entry2 | ... | restarts(uint32 * num_of_restarts) | num_of_restarts(uint32) | trailer 其中entry格式为: shared_bytes(varint32) | unshared_bytes(varint32) | value_bytes(varint32) | unshared_key_data(unshared_bytes) | value_data(value_bytes) shared_bytes为这个entry中的key与前一个entry的key共享的字节数,entry的key在存储时只存储不共享的部分,即采用前缀压缩的形式,并且前缀压缩是分组进行的,以避免所有查找都需要从头开始的情况。而每个组的起始entry的位置(offset)存储在restarts中,每个为uint32,数量为num_of_restarts。 trailer的格式为: type(char) | crc(uint32) type为block的压缩方式,crc为循环冗余校验码。 Block类 Block类对sstable的block中的数据进行封装,并提供了一个迭代器作为接口。Block类的声明为: class Block { public: // ... private: // ... const char *data_; size_t size_; uint32_t restart_offset_; // Offset in data_ of restart array bool owned_; // Block owns data_[] // ... class Iter; }; 其中成员变量data_为指向block中数据的指针,size_为block中数据的大小,restart_offset_为block中restarts部分数据的起始位置的offset,owned标记block是否包含data_。 而LevelDB实际上为Block类封装了一个Iter类,对Block的遍历操作需要通过Iter类提供的接口函数进行。 class Block::Iter : public Iterator { private: const Comparator *const comparator_; const char *const data_; // underlying block contents uint32_t const restarts_; // Offset of restart array (list of fixed32) uint32_t const num_restarts_; // Number of uint32_t entries in restart array // current_ is offset in data_ of current entry. >= restarts_ if !Valid uint32_t current_; uint32_t restart_index_; // Index of restart block in which current_ falls std::string key_; Slice value_; Status status_; // ... public: // ... virtual bool Valid() const { return current_ < restarts_; } virtual Status status() const { return status_; } virtual Slice key() const { // ... } virtual Slice value() const { // ... } virtual void Next() { // ... } virtual void Prev() { // ... } virtual void Seek(const Slice &target) { // 见下文分析 } virtual void SeekToFirst() { // ... } virtual void SeekToLast() { // ... } private: // ... }; 其中,前几个成员变量的含义与Block类中的成员变量的含义类似,这里不再赘述。key_、value_这两个成员变量为迭代器当前指向的entry的KV值。 在这里主要分析Seek(const Slice &target)函数,其余函数的实现比较简单,在这里就不做分析了。Seek函数首先通过二分查找算法找到target所在的前缀编码分组的位置: // Binary search in restart array to find the last restart point // with a key < target uint32_t left = 0; uint32_t right = num_restarts_ - 1; while (left < right) { uint32_t mid = (left + right + 1) / 2; uint32_t region_offset = GetRestartPoint(mid); uint32_t shared, non_shared, value_length; const char *key_ptr = DecodeEntry(data_ + region_offset, data_ + restarts_, &shared, &non_shared, &value_length); if (key_ptr == nullptr || (shared != 0)) { CorruptionError(); return; } Slice mid_key(key_ptr, non_shared); if (Compare(mid_key, target) < 0) { // Key at "mid" is smaller than "target". Therefore all // blocks before "mid" are uninteresting. left = mid; } else { // Key at "mid" is >= "target". Therefore all blocks at or // after "mid" are uninteresting. right = mid - 1; } } 然后在该分组中遍历: // Linear search (within restart block) for first key >= target SeekToRestartPoint(left); while (true) { if (!ParseNextKey()) { return; } if (Compare(key_, target) >= 0) { return; } } 其中调用了DecodeEntry函数: static inline const char *DecodeEntry(const char *p, const char *limit, uint32_t *shared, uint32_t *non_shared, uint32_t *value_length) { // ... } 这个函数将以p为起始位置的entry解码,并且解码不会超过limit指向的位置,将key共享字节长度、key非共享字节长度、value长度存入shared,non_shared,value_length,返回指向entry中unshared_key_data起始位置的指针。 还调用了ParseNextKey函数: bool ParseNextKey() { // ... } 这个函数获取下一个entry的key和value值并存入迭代器的成员变量中。 BlockBuilder类 BlockBuilder类用于构建sstable中的block。BlockBuilder类声明为: class BlockBuilder { public: // ... // REQUIRES: Finish() has not been called since the last call to Reset(). // REQUIRES: key is larger than any previously added key void Add(const Slice &key, const Slice &value); // Finish building the block and return a slice that refers to the // block contents. The returned slice will remain valid for the // lifetime of this builder or until Reset() is called. Slice Finish(); // ... private: const Options *options_; std::string buffer_; // Destination buffer std::vector<uint32_t> restarts_; // Restart points int counter_; // Number of entries emitted since restart bool finished_; // Has Finish() been called? std::string last_key_; // ... }; 其中options_为构建选项,buffer_为实际block中的数据,restarts_存储前缀编码各个分组的起始位置,counter_记录当前前缀编码分组中已经压缩了几个entry,finished_标记Finish是否被调用,last_key_为block中上一次添加的key值。 下面我们首先看Add函数: void BlockBuilder::Add(const Slice &key, const Slice &value) Add函数首先检查当前前缀编码分组中压缩的entry个数是否已经达到上限,如果没有达到上限则计算共享的key的字节个数: Slice last_key_piece(last_key_); assert(!finished_); assert(counter_ <= options_->block_restart_interval); assert(buffer_.empty() // No values yet? || options_->comparator->Compare(key, last_key_piece) > 0); size_t shared = 0; if (counter_ < options_->block_restart_interval) { // See how much sharing to do with previous string const size_t min_length = std::min(last_key_piece.size(), key.size()); while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { shared++; } } 如果达到上限则重新开始一个restart: else { // Restart compression restarts_.push_back(buffer_.size()); counter_ = 0; } const size_t non_shared = key.size() - shared; 然后依次将相应的数据编码后组成一个新的entry: // Add "<shared><non_shared><value_size>" to buffer_ PutVarint32(&buffer_, shared); PutVarint32(&buffer_, non_shared); PutVarint32(&buffer_, value.size()); // Add string delta to buffer_ followed by value buffer_.append(key.data() + shared, non_shared); buffer_.append(value.data(), value.size()); 最后将数据加在buffer_的后面并更新last_key_和counter_的值: // Update state last_key_.resize(shared); last_key_.append(key.data() + shared, non_shared); assert(Slice(last_key_) == key); counter_++; 然后是Finish函数: Slice BlockBuilder::Finish() { // Append restart array for (size_t i = 0; i < restarts_.size(); i++) { PutFixed32(&buffer_, restarts_[i]); } PutFixed32(&buffer_, restarts_.size()); finished_ = true; return Slice(buffer_); } Finish函数首先将restarts_的偏移量存入buffer_,然后存入num_of_restarts,然后将buffer_封装为一个Slice返回。 228 Love u

优秀的个人博客,低调大师

datax源码阅读二:Engine流程

一、根据前面python文件知道,java的main函数是com.alibaba.datax.core.Engine public static void main(String[] args) throws Exception { int exitCode = 0; try { Engine.entry(args); } catch (Throwable e) { exitCode = 1; String trace = ExceptionTracker.trace(e); String errDesc = "未知datax错误,参考堆栈内容分析。"; LOG.error("\n\n经DataX智能分析,该任务最可能的错误原因是:\n" + trace); if (e instanceof DataXException) { DataXException tempException = (DataXException) e; ErrorCode errorCode = tempException.getErrorCode(); errDesc = errorCode.getDescription(); if (errorCode instanceof FrameworkErrorCode) { FrameworkErrorCode tempErrorCode = (FrameworkErrorCode) errorCode; exitCode = tempErrorCode.toExitValue(); } } System.exit(exitCode); } System.exit(exitCode); } main函数主要catch了一下异常,并将异常信息打印出来,实际执行在entry函数中 public static void entry(final String[] args) throws Throwable { Options options = new Options(); options.addOption("job", true, "Job config."); options.addOption("jobid", true, "Job unique id."); options.addOption("mode", true, "Job runtime mode."); BasicParser parser = new BasicParser(); CommandLine cl = parser.parse(options, args); String jobPath = cl.getOptionValue("job"); // 如果用户没有明确指定jobid, 则 datax.py 会指定 jobid 默认值为-1 String jobIdString = cl.getOptionValue("jobid"); RUNTIME_MODE = cl.getOptionValue("mode"); Configuration configuration = ConfigParser.parse(jobPath); long jobId; if (!"-1".equalsIgnoreCase(jobIdString)) { jobId = Long.parseLong(jobIdString); } else { // only for dsc & ds & datax 3 update String dscJobUrlPatternString = "/instance/(\\d{1,})/config.xml"; String dsJobUrlPatternString = "/inner/job/(\\d{1,})/config"; String dsTaskGroupUrlPatternString = "/inner/job/(\\d{1,})/taskGroup/"; List<String> patternStringList = Arrays.asList(dscJobUrlPatternString, dsJobUrlPatternString, dsTaskGroupUrlPatternString); jobId = parseJobIdFromUrl(patternStringList, jobPath); } boolean isStandAloneMode = "standalone".equalsIgnoreCase(RUNTIME_MODE); if (!isStandAloneMode && jobId == -1) { // 如果不是 standalone 模式,那么 jobId 一定不能为-1 throw DataXException.asDataXException(FrameworkErrorCode.CONFIG_ERROR, "非 standalone 模式必须在 URL 中提供有效的 jobId."); } configuration.set(CoreConstant.DATAX_CORE_CONTAINER_JOB_ID, jobId); //打印vmInfo VMInfo vmInfo = VMInfo.getVmInfo(); if (vmInfo != null) { LOG.info(vmInfo.toString()); } LOG.info("\n" + Engine.filterJobConfiguration(configuration) + "\n"); LOG.debug(configuration.toJSON()); ConfigurationValidate.doValidate(configuration); Engine engine = new Engine(); engine.start(configuration); } entry函数主要功能: 1、解析了java命令行的三个参数,分别是job、jobid和mode,其中job是用户配置的json文件路径,jobid和mode是python文件带进来的,单机模式下可以忽略改参数 2、读取用户配置的json文件,转化为内部的configuration配置 3、打印相关信息,并校验json文件的合法性 4、启动engine执行 entry执行完毕之后,进入start函数,关键代码如下: public void start(Configuration allConf) { // 绑定column转换信息 ColumnCast.bind(allConf); /** * 初始化PluginLoader,可以获取各种插件配置 */ LoadUtil.bind(allConf); ************* container = new JobContainer(allConf); ************* container.start(); } start函数中主要包括: 1、列转换默认值,即动态在configuration中注入默认值 2、初始化插件的LoadUtil,后面classLoader相关操作都会依赖这个函数 3、初始化JobContainer并启动

优秀的个人博客,低调大师

java源码-java.util.List

public List<String> findAddressesByApplication(String application) { List<String> ret = new ArrayList<String>(); ConcurrentMap<String, Map<Long, URL>> consumerUrls = getRegistryCache().get(Constants.CONSUMERS_CATEGORY); if(consumerUrls == null) return ret; for(Map.Entry<String, Map<Long, URL>> e1 : consumerUrls.entrySet()) { Map<Long, URL> value = e1.getValue(); for(Map.Entry<Long, URL> e2 : value.entrySet()) { URL u = e2.getValue(); if(application.equals(u.getParameter(Constants.APPLICATION_KEY))) { String addr = u.getAddress(); if(addr != null) ret.add(addr); } } } return ret; } 原文:http://www.codingdict.com/sources/java/java.util/5364.html

优秀的个人博客,低调大师

Java 源码解析实战 - ThreadLocal 原理

说起CS游戏,应该是每个中二少年的年少回忆了.游戏开始时,每个人能够领到一把枪,枪把上有三个数字:子弹数、杀敌数、自己的命数,为其设置的初始值分别为1500、0、10. 设战场上的每个人都是一个线程,那么这三个初始值写在哪里呢?如果每个线程都写死这三个值,万一将初始子弹数统一改成 1000发呢?如果共享,那么线程之间的并发修改会导致数据不准确.能不能构造这样一个对象,将这个对象设置为共享变量,统一设置初始值,但是每个线程对这个值的修改都是互相独立的.这个对象就是ThreadLocal 注意不能将其翻译为线程本地化或本地线程英语恰当的名称应该叫作:CopyValueIntoEveryThread 示例代码该示例中,无 set 操作,那么初始值又是如何进入每个线程成为独立拷贝的呢?首先,虽然ThreadLocal在定义时重写了initial

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册