??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲综合色区中文字幕,亚洲AV无码专区国产乱码4SE ,亚洲va成无码人在线观看http://m.tkk7.com/sandy/archive/2012/03/21/leveldb11.htmlWed, 21 Mar 2012 09:30:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/21/leveldb11.htmlhttp://m.tkk7.com/sandy/comments/372372.htmlhttp://m.tkk7.com/sandy/archive/2012/03/21/leveldb11.html#Feedback1http://m.tkk7.com/sandy/comments/commentRss/372372.htmlhttp://m.tkk7.com/sandy/services/trackbacks/372372.html
先看看ReadOptions有哪些参数可以指定:(x)
// Options that control read operations
struct ReadOptions {
  
// 是否(g)查checksum
  
// Default: false
  bool verify_checksums;

  
// 是否此ơ结果放入cache
  
// Default: true
  bool fill_cache;

  
//是否指定snapshot,否则d当前版本
  
// Default: NULL
  const Snapshot* snapshot;

  ReadOptions()
      : verify_checksums(
false),
        fill_cache(
true),
        snapshot(NULL) {
  }
};

下面看看d的详l过E:(x)
查询memtable=>查询previous memtable(imm_)=>查询文g(~冲Q?br />
Status DBImpl::Get(const ReadOptions& options,
                   
const Slice& key,
                   std::
string* value) {
  Status s;
  MutexLock l(
&mutex_);
  SequenceNumber snapshot;
  
//讄snapshot
  if (options.snapshot != NULL) {
    snapshot 
= reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
  } 
else {
    snapshot 
= versions_->LastSequence();
  }

  MemTable
* mem = mem_;
  MemTable
* imm = imm_;
  Version
* current = versions_->current();
  mem
->Ref();
  
if (imm != NULL) imm->Ref();
  current
->Ref();

  
bool have_stat_update = false;
  Version::GetStats stats;

  
// Unlock while reading from files and memtables
  {
    mutex_.Unlock();
    LookupKey lkey(key, snapshot);
    
//先查询memtable
    if (mem->Get(lkey, value, &s)) {
      
// Done
    } else if (imm != NULL && imm->Get(lkey, value, &s)) { //然后查询previous memtable:imm_
      
// Done
    } else {
      
//从文件中d
      s = current->Get(options, lkey, value, &stats);
      have_stat_update 
= true;
    }
    mutex_.Lock();
  }

  
//是否有文仉要被compaction,参见allowed_seek
  if (have_stat_update && current->UpdateStats(stats)) {
    MaybeScheduleCompaction();
  }
  mem
->Unref();
  
if (imm != NULL) imm->Unref();
  current
->Unref();
  
return s;
}


重点来看看从version中读取:(x)
Status Version::Get(const ReadOptions& options,
                    
const LookupKey& k,
                    std::
string* value,
                    GetStats
* stats) {
  Slice ikey 
= k.internal_key();
  Slice user_key 
= k.user_key();
  
const Comparator* ucmp = vset_->icmp_.user_comparator();
  Status s;

  stats
->seek_file = NULL;
  stats
->seek_file_level = -1;
  FileMetaData
* last_file_read = NULL;
  
int last_file_read_level = -1;

  
//从level0向高层查找,如果再低Ulevel中查刎ͼ则不再查?/span>
  std::vector<FileMetaData*> tmp;
  FileMetaData
* tmp2;
  
for (int level = 0; level < config::kNumLevels; level++) {
    size_t num_files 
= files_[level].size();
    
//本层文gCؓ(f)I,则返?/span>
    if (num_files == 0continue;

    
// Get the list of files to search in this level
    FileMetaData* const* files = &files_[level][0];
    
if (level == 0) {
      
//level0Ҏ(gu)处理Q因为key是重叠,所有符合条件的文g必须被查?/span>
      tmp.reserve(num_files);
      
for (uint32_t i = 0; i < num_files; i++) {
        FileMetaData
* f = files[i];
        
if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
            ucmp
->Compare(user_key, f->largest.user_key()) <= 0) {
          tmp.push_back(f);
        }
      }
      
if (tmp.empty()) continue;

      std::sort(tmp.begin(), tmp.end(), NewestFirst);
      files 
= &tmp[0];
      num_files 
= tmp.size();
    } 
else {
      
// 二分法查找,某个key只可能属于一个文?/span>
      uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);
      
//没有查到
      if (index >= num_files) {
        files 
= NULL;
        num_files 
= 0;
      } 
else {
        tmp2 
= files[index];
        
if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) {
          
// All of "tmp2" is past any data for user_key
          files = NULL;
          num_files 
= 0;
        } 
else {
          files 
= &tmp2;
          num_files 
= 1;
        }
      }
    }

    
for (uint32_t i = 0; i < num_files; ++i) { //遍历本层W合条g的文?/span>
      if (last_file_read != NULL && stats->seek_file == NULL) {
        
//seek_file只记录第一?/span>
        stats->seek_file = last_file_read;
        stats
->seek_file_level = last_file_read_level;
      }

      FileMetaData
* f = files[i];
      last_file_read 
= f;
      last_file_read_level 
= level;
      
      
//从table cache中读?/span>
      Iterator* iter = vset_->table_cache_->NewIterator(
          options,
          f
->number,
          f
->file_size);
      iter
->Seek(ikey);
      
const bool done = GetValue(ucmp, iter, user_key, value, &s);
      
if (!iter->status().ok()) { //查找?/span>
        s = iter->status();
        delete iter;
        
return s;
      } 
else {
        delete iter;
        
if (done) {
          
return s;
        }
      }
    }
  }

  
return Status::NotFound(Slice());  // Use an empty error message for speed
}

l箋(hu)跟踪QTableCache

Iterator* TableCache::NewIterator(const ReadOptions& options,
                                  uint64_t file_number,
                                  uint64_t file_size,
                                  Table
** tableptr) {
  
if (tableptr != NULL) {
    
*tableptr = NULL;
  }

  
char buf[sizeof(file_number)];
  EncodeFixed64(buf, file_number);
  Slice key(buf, 
sizeof(buf));

  
//从LRU cache中查?/span>
  Cache::Handle* handle = cache_->Lookup(key);
  
if (handle == NULL) { 
    
/加蝲文g
    std::
string fname = TableFileName(dbname_, file_number);
    RandomAccessFile
* file = NULL;
    Table
* table = NULL;
    Status s 
= env_->NewRandomAccessFile(fname, &file);
    
if (s.ok()) {
      s 
= Table::Open(*options_, file, file_size, &table);
    }

    
if (!s.ok()) {
      assert(table 
== NULL);
      delete file;
      
// We do not cache error results so that if the error is transient,
      
// or somebody repairs the file, we recover automatically.
      return NewErrorIterator(s);
    }

    
//插入Cache
    TableAndFile* tf = new TableAndFile;
    tf
->file = file;
    tf
->table = table;
    handle 
= cache_->Insert(key, tf, 1&DeleteEntry);
  }

  Table
* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
  
//从Table对象中生成iterator
  Iterator* result = table->NewIterator(options);
  result
->RegisterCleanup(&UnrefEntry, cache_, handle);
  
if (tableptr != NULL) {
    
*tableptr = table;
  }
  
return result;
}




2012-03-21 17:30 发表评论
]]>
leveldb研究10- 程分析Q写数据http://m.tkk7.com/sandy/archive/2012/03/21/leveldb10.htmlWed, 21 Mar 2012 06:41:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/21/leveldb10.htmlhttp://m.tkk7.com/sandy/comments/372345.htmlhttp://m.tkk7.com/sandy/archive/2012/03/21/leveldb10.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/372345.htmlhttp://m.tkk7.com/sandy/services/trackbacks/372345.html
影响写性能的因素有Q?br />1. write_buffer_size
2. kL0_SlowdownWritesTrigger and kL0_StopWritesTrigger.提高q两个|能够增加写的性能Q但是降低读的性能

看看WriteOptions有哪些参数可以指?br />
struct WriteOptions {
  
//讄sync=true,leveldb?x)调用fsync()Q这?x)降低插入性能
  
//同时?x)增加数据的安全?nbsp;
  
//Default: false
  bool sync;

  WriteOptions()
      : sync(
false) {
  }
};


首先把Key,value转成WriteBatch
Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) {
  WriteBatch batch;
  batch.Put(key, value);
  
return Write(opt, &batch);
}

接下来就是真正的插入?br />q里使用?jin)两把锁Q主要是x(chng)高ƈ发能力,减少上锁的时间?br />首先是检查是否可写,然后append logQ最后是插入memtable
<db/dbimpl.cc>

Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
  Status status;
  
//加锁
  MutexLock l(&mutex_);
  LoggerId self;
  
//拿到写log的权?/span>
  AcquireLoggingResponsibility(&self);
  
//(g)查是否可?/span>
  status = MakeRoomForWrite(false);  // May temporarily release lock and wait
  uint64_t last_sequence = versions_->LastSequence();
  
if (status.ok()) {
    WriteBatchInternal::SetSequence(updates, last_sequence 
+ 1);
    last_sequence 
+= WriteBatchInternal::Count(updates);

    
// Add to log and apply to memtable.  We can release the lock during
    
// this phase since the "logger_" flag protects against concurrent
    
// loggers and concurrent writes into mem_.
    {
      assert(logger_ 
== &self);
      mutex_.Unlock();
      
//IO操作Q写入LOG
      status = log_->AddRecord(WriteBatchInternal::Contents(updates));
      
if (status.ok() && options.sync) {
        status 
= logfile_->Sync();
      }
      
//插入memtable
      if (status.ok()) {
        status 
= WriteBatchInternal::InsertInto(updates, mem_);
      }
      mutex_.Lock();
      assert(logger_ 
== &self);
    }
    
//讄新的seqence number
    versions_->SetLastSequence(last_sequence);
  }
  
//释放写LOG?/span>
  ReleaseLoggingResponsibility(&self);
  
return status;
}

写流量控Ӟ(x)
<db/dbimpl.cc>
Status DBImpl::MakeRoomForWrite(bool force) {
  mutex_.AssertHeld();
  assert(logger_ 
!= NULL);
  
bool allow_delay = !force;
  Status s;
  
while (true) {
    
if (!bg_error_.ok()) {
      
// Yield previous error
      s = bg_error_;
      
break;
    } 
else if ( 
        allow_delay 
&&
        versions_
->NumLevelFiles(0>= config::kL0_SlowdownWritesTrigger) {
      mutex_.Unlock();
      
//如果level0的文件大于kL0_SlowdownWritesTrigger阈|则sleep 1sQ这L(fng)compaction更多的CPU
      env_->SleepForMicroseconds(1000);
      allow_delay 
= false;  // Do not delay a single write more than once
      mutex_.Lock();
    } 
else if (!force &&
               (mem_
->ApproximateMemoryUsage() <= options_.write_buffer_size)) {
      
//可写
      break;
    } 
else if (imm_ != NULL) {
      
// imm_:之前的memtable 没有被compactionQ需要等?/span>
      bg_cv_.Wait();
    } 
else if (versions_->NumLevelFiles(0>= config::kL0_StopWritesTrigger) {
      
// level0文g个数大于kL0_StopWritesTrigger,需要等?/span>
      Log(options_.info_log, "waiting\n");
      bg_cv_.Wait();
    } 
else {
      
//生成新的额memtable和logfileQ把当前memtable传给imm_
      assert(versions_->PrevLogNumber() == 0);
      uint64_t new_log_number 
= versions_->NewFileNumber();
      WritableFile
* lfile = NULL;
      s 
= env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
      
if (!s.ok()) {
        
break;
      }
      delete log_;
      delete logfile_;
      logfile_ 
= lfile;
      logfile_number_ 
= new_log_number;
      log_ 
= new log::Writer(lfile);
      imm_ 
= mem_;
      has_imm_.Release_Store(imm_);
      mem_ 
= new MemTable(internal_comparator_);
      mem_
->Ref();
      force 
= false;   // Do not force another compaction if have room
      // 发vcompaction,dump imm_
      MaybeScheduleCompaction();
    }
  }
  
return s;
}



2012-03-21 14:41 发表评论
]]>
leveldb研究9- 程分析Q打开数据?/title><link>http://m.tkk7.com/sandy/archive/2012/03/20/leveldb9.html</link><dc:creator>明</dc:creator><author>明</author><pubDate>Tue, 20 Mar 2012 08:02:00 GMT</pubDate><guid>http://m.tkk7.com/sandy/archive/2012/03/20/leveldb9.html</guid><wfw:comment>http://m.tkk7.com/sandy/comments/372251.html</wfw:comment><comments>http://m.tkk7.com/sandy/archive/2012/03/20/leveldb9.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/sandy/comments/commentRss/372251.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/sandy/services/trackbacks/372251.html</trackback:ping><description><![CDATA[     摘要: leveldb 是通过Open函数来打开/新徏数据库。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->static Status Open(const Options& options, &nb...  <a href='http://m.tkk7.com/sandy/archive/2012/03/20/leveldb9.html'>阅读全文</a><img src ="http://m.tkk7.com/sandy/aggbug/372251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/sandy/" target="_blank">明</a> 2012-03-20 16:02 <a href="http://m.tkk7.com/sandy/archive/2012/03/20/leveldb9.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>leveldb研究8- 内存?sh)的数据l构Memtable/SkipListhttp://m.tkk7.com/sandy/archive/2012/03/19/leveldb8.htmlMon, 19 Mar 2012 08:31:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/19/leveldb8.htmlhttp://m.tkk7.com/sandy/comments/372177.htmlhttp://m.tkk7.com/sandy/archive/2012/03/19/leveldb8.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/372177.htmlhttp://m.tkk7.com/sandy/services/trackbacks/372177.html
先看看SkipList【蟩表】这个数据结构:(x)


SkipList有如下特点:(x)
1. 本质上一个排序好的链?br />2. 分层Q上层节Ҏ(gu)下层的少Q更h跌?br />3. 查询的复杂度是O(logn)

SkipList跟红黑树(wi){还是比较容易实现和理解的,主要长处是比较容易实现Lock free和遍历?br />我们来看看leveldb的实?br />插入Q?br />
//插入一个新的key
template<typename Key, class Comparator>
void SkipList<Key,Comparator>::Insert(const Key& key) {
  
//查找插入节点,prev为各层的前置节点
  Node* prev[kMaxHeight];
  Node
* x = FindGreaterOrEqual(key, prev);

  
// Our data structure does not allow duplicate insertion
  assert(x == NULL || !Equal(key, x->key));

  
//生成随机高度
  int height = RandomHeight();
  
if (height > GetMaxHeight()) {
    
for (int i = GetMaxHeight(); i < height; i++) {
      prev[i] 
= head_;
    }
    
//讄当前最大高?/span>
    max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
  }

  
//生成新节?/span>
  x = NewNode(key, height);
  
for (int i = 0; i < height; i++) {
    
//讄新节点的各层的下一?/span>
    x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
    
//讄前节点的next为当前节点,完成插入
    prev[i]->SetNext(i, x);
  }
}

查询Q?br />
template<typename Key, class Comparator>
typename SkipList
<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
    
const {
  Node
* x = head_;
  
int level = GetMaxHeight() - 1//从高层开始查找,依次? level
  while (true) {
    Node
* next = x->Next(level); 
    
if (KeyIsAfterNode(key, next)) { //比next key 要大
      
// Keep searching in this list
      x = next;
    } 
else { //比next key,查找下一?br />      //标记当前level的前|节?/span>
      if (prev != NULL) prev[level] = x;
      
if (level == 0) {
        
return next;
      } 
else {
        level
--;
      }
    }
  }
}

template
<typename Key, class Comparator>
bool SkipList<Key,Comparator>::Contains(const Key& key) const {
  Node
* x = FindGreaterOrEqual(key, NULL);
  
if (x != NULL && Equal(key, x->key)) {
    
return true;
  } 
else {
    
return false;
  }
}


接着我们看看leveldb MemTable的实玎ͼ很简单了(jin)Q基本是对SkipList讉K一个封?br /><db/memtable.h>
class MemTable {
 
public:
  
explicit MemTable(const InternalKeyComparator& comparator);

  
//增加引用计数
  void Ref() { ++refs_; }

  
//减少引用计数
  void Unref() {
    
--refs_;
    assert(refs_ 
>= 0);
    
if (refs_ <= 0) {
      delete 
this;
    }
  }

  
//内存?sh)用?/span>
  size_t ApproximateMemoryUsage();

  
//遍历操作
  Iterator* NewIterator();

  
//插入
  void Add(SequenceNumber seq, ValueType type,
           
const Slice& key,
           
const Slice& value);

  
//查询
  bool Get(const LookupKey& key, std::string* value, Status* s);

 
private:
  
~MemTable();  // Private since only Unref() should be used to delete it

  
//key compartorQ用于排?/span>
  struct KeyComparator {
    
const InternalKeyComparator comparator;
    
explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { }
    
int operator()(const char* a, const char* b) const;
  };
  friend 
class MemTableIterator;
  friend 
class MemTableBackwardIterator;

  typedef SkipList
<const char*, KeyComparator> Table;

  KeyComparator comparator_;
  
int refs_; //引用计数
  Arena arena_; //内存分配?/span>
  Table table_; //数据存放SkipList

  
// No copying allowed
  MemTable(const MemTable&);
  
void operator=(const MemTable&);
};

先看看插?br /><db/memtable.cc>
void MemTable::Add(SequenceNumber s, ValueType type,
                   
const Slice& key,
                   
const Slice& value) {
  
//数据l构Q?br />  //1.internal key size : Varint32 (length of 2+3)
  
//2.key data
  
//3.SequenceNumber+Key type: 8 bytes
  
//4 value size: Varint32
  
//5 value data
  size_t key_size = key.size();
  size_t val_size 
= value.size();
  size_t internal_key_size 
= key_size + 8;
  
const size_t encoded_len =
      VarintLength(internal_key_size) 
+ internal_key_size +
      VarintLength(val_size) 
+ val_size;
  
char* buf = arena_.Allocate(encoded_len);
  
char* p = EncodeVarint32(buf, internal_key_size);
  memcpy(p, key.data(), key_size);
  p 
+= key_size;
  EncodeFixed64(p, (s 
<< 8| type);
  p 
+= 8;
  p 
= EncodeVarint32(p, val_size);
  memcpy(p, value.data(), val_size);
  assert((p 
+ val_size) - buf == encoded_len);
  table_.Insert(buf);
}

查询
<db/memtable.cc>
bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {
  Slice memkey 
= key.memtable_key();
  Table::Iterator iter(
&table_);
  iter.Seek(memkey.data());
  
if (iter.Valid()) {
    
// entry format is:
    
//    klength  varint32
    
//    userkey  char[klength]
    
//    tag      uint64
    
//    vlength  varint32
    
//    value    char[vlength]
    
// Check that it belongs to same user key.  We do not check the
    
// sequence number since the Seek() call above should have skipped
    
// all entries with overly large sequence numbers.
    const char* entry = iter.key();
    uint32_t key_length;
    
const char* key_ptr = GetVarint32Ptr(entry, entry+5&key_length);
    
if (comparator_.comparator.user_comparator()->Compare(
            Slice(key_ptr, key_length 
- 8),
            key.user_key()) 
== 0) {
      
// Correct user key
      const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);
      
switch (static_cast<ValueType>(tag & 0xff)) {
        
case kTypeValue: {
          Slice v 
= GetLengthPrefixedSlice(key_ptr + key_length);
          value
->assign(v.data(), v.size());
          
return true;
        }
        
case kTypeDeletion:
          
*= Status::NotFound(Slice());
          
return true;
      }
    }
  }
  
return false;
}


2012-03-19 16:31 发表评论
]]>
leveldb研究7-Version/VersionSet/VersionEdithttp://m.tkk7.com/sandy/archive/2012/03/16/leveldb7.htmlFri, 16 Mar 2012 09:10:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/16/leveldb7.htmlhttp://m.tkk7.com/sandy/comments/372028.htmlhttp://m.tkk7.com/sandy/archive/2012/03/16/leveldb7.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/372028.htmlhttp://m.tkk7.com/sandy/services/trackbacks/372028.html
先看看一个重要的数据l果Qsst file的META info
<db/version_edit.h>

struct FileMetaData {
  
int refs; //引用计数
  int allowed_seeks; //允许的seeksơ数
  uint64_t number;//文g~号
  uint64_t file_size;  //文g大小
  InternalKey smallest;    //最的key
  InternalKey largest;      //最大的key 

  FileMetaData() : refs(
0), allowed_seeks(1 << 30), file_size(0) { }
};

q里面有一个很有意思的字段: allowed_seeks,代表?jin)可以seek的次敎ͼ?的时候表C个文仉要被compaction.如何讄seeksơ数呢?文g大小除以16kQ不?00?00?br />
      f->allowed_seeks = (f->file_size / 16384);
      
if (f->allowed_seeks < 100) f->allowed_seeks = 100;

原因Q请看leveldb的注释:(x)

// We arrange to automatically compact this file after a certain number of seeks.  Let's assume:
      //   (1) One seek costs 10ms
      //   (2) Writing or reading 1MB costs 10ms (100MB/s)
      //   (3) A compaction of 1MB does 25MB of IO:
      //         1MB read from this level
      //         10-12MB read from next level (boundaries may be misaligned)
      //         10-12MB written to next level
      // This implies that 25 seeks cost the same as the compaction
      // of 1MB of data.  I.e., one seek costs approximately the
      // same as the compaction of 40KB of data.  We are a little
      // conservative and allow approximately one seek for every 16KB
      // of data before triggering a compaction.


接下来看Version的定义,version其实是一pd的SST file的集合?br />
class Version {
 
public:
  
//生成iterator用于遍历
  void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);

  
//Ҏ(gu)key来查询,若没有查刎ͼ更新GetStats
  struct GetStats {
    FileMetaData
* seek_file;
    
int seek_file_level;
  };
  Status Get(
const ReadOptions&const LookupKey& key, std::string* val,
             GetStats
* stats);

  
//是否需要进行compaction
  bool UpdateStats(const GetStats& stats);

  
//引用计算Q避免在被引用时候删?/span>
  void Ref();
  
void Unref();

  
//查询和key range有关的files
  void GetOverlappingInputs(
      
int level,
      
const InternalKey* begin,         // NULL means before all keys
      const InternalKey* end,           // NULL means after all keys
      std::vector<FileMetaData*>* inputs);

  
//计算是否levelҎ(gu)个key range是否有overlap
  bool OverlapInLevel(int level,
                      
const Slice* smallest_user_key,
                      
const Slice* largest_user_key);

  
//memtable output应该攑ֈ哪个level
  int PickLevelForMemTableOutput(const Slice& smallest_user_key,
                                 
const Slice& largest_user_key);

  
//某个level的文件个?/span>
   int NumFiles(int level) const { return files_[level].size(); }

  
// Return a human readable string that describes this version's contents.
  std::string DebugString() const;

 
private:
  friend 
class Compaction;
  friend 
class VersionSet;

  
class LevelFileNumIterator;
  Iterator
* NewConcatenatingIterator(const ReadOptions&int level) const;

  VersionSet
* vset_;            // VersionSet to which this Version belongs
  Version* next_;               // Next version in linked list
  Version* prev_;               // Previous version in linked list
  int refs_;                    // Number of live refs to this version

  
//sst files 
  std::vector<FileMetaData*> files_[config::kNumLevels];

  
//下一个要被compaction的文?/span>
  FileMetaData* file_to_compact_;
  
int file_to_compact_level_;

  
//compaction score:>1表示要compaction
  double compaction_score_;
  
int compaction_level_;

  
explicit Version(VersionSet* vset)
      : vset_(vset), next_(
this), prev_(this), refs_(0),
        file_to_compact_(NULL),
        file_to_compact_level_(
-1),
        compaction_score_(
-1),
        compaction_level_(
-1) {
  }

  
~Version();

  
// No copying allowed
  Version(const Version&);
  
void operator=(const Version&);
};


那VersionSet呢?VersionSet 是versionl成一个双向@环链表?br />
class VersionSet{
//. . .
Env* const env_;
  
const std::string dbname_;
  
const Options* const options_;
  TableCache
* const table_cache_;
  
const InternalKeyComparator icmp_;
  uint64_t next_file_number_;
  uint64_t manifest_file_number_;
  uint64_t last_sequence_;
  uint64_t log_number_;

  WritableFile
* descriptor_file_;
  log::Writer
* descriptor_log_;
  Version dummy_versions_;  
// Head of circular doubly-linked list of versions.
  Version* current_;        // == dummy_versions_.prev_

  
//每层都有一个compact pointer用于指示下次从哪里开始compact,以用于实现@环compact
  std::string compact_pointer_[config::kNumLevels];
//. . .
}


VersionEdit是version对象的变更记录,用于写入manifest.q样通过原始的version加上一pd的versionedit的记录,可以恢复到最新状态?br />
class VersionEdit {
 
public:
  VersionEdit() { Clear(); }
  
~VersionEdit() { }

  
void Clear();

  
void SetComparatorName(const Slice& name) {
    has_comparator_ 
= true;
    comparator_ 
= name.ToString();
  }
  
void SetLogNumber(uint64_t num) {
    has_log_number_ 
= true;
    log_number_ 
= num;
  }
  
void SetPrevLogNumber(uint64_t num) {
    has_prev_log_number_ 
= true;
    prev_log_number_ 
= num;
  }
  
void SetNextFile(uint64_t num) {
    has_next_file_number_ 
= true;
    next_file_number_ 
= num;
  }
  
void SetLastSequence(SequenceNumber seq) {
    has_last_sequence_ 
= true;
    last_sequence_ 
= seq;
  }
  
void SetCompactPointer(int level, const InternalKey& key) {
    compact_pointers_.push_back(std::make_pair(level, key));
  }

  
//dmeta file
  void AddFile(int level, uint64_t file,
               uint64_t file_size,
               
const InternalKey& smallest,
               
const InternalKey& largest) {
    FileMetaData f;
    f.number 
= file;
    f.file_size 
= file_size;
    f.smallest 
= smallest;
    f.largest 
= largest;
    new_files_.push_back(std::make_pair(level, f));
  }

  
//删除特定的文?/span>
  void DeleteFile(int level, uint64_t file) {
    deleted_files_.insert(std::make_pair(level, file));
  }

  
//~码Q解码:(x)用于写入manifest
  void EncodeTo(std::string* dst) const;
  Status DecodeFrom(
const Slice& src);

  std::
string DebugString() const;

 
private:
  friend 
class VersionSet;

  typedef std::
set< std::pair<int, uint64_t> > DeletedFileSet;

  std::
string comparator_;
  uint64_t log_number_;
  uint64_t prev_log_number_;
  uint64_t next_file_number_;
  SequenceNumber last_sequence_;
  
bool has_comparator_;
  
bool has_log_number_;
  
bool has_prev_log_number_;
  
bool has_next_file_number_;
  
bool has_last_sequence_;

  std::vector
< std::pair<int, InternalKey> > compact_pointers_;
  DeletedFileSet deleted_files_;
  std::vector
< std::pair<int, FileMetaData> > new_files_;
};




2012-03-16 17:10 发表评论
]]>
leveldb研究6- Level和Compactionhttp://m.tkk7.com/sandy/archive/2012/03/15/leveldb6.htmlThu, 15 Mar 2012 09:28:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/15/leveldb6.htmlhttp://m.tkk7.com/sandy/comments/371848.htmlhttp://m.tkk7.com/sandy/archive/2012/03/15/leveldb6.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/371848.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371848.html阅读全文

2012-03-15 17:28 发表评论
]]>
leveldb研究5- Snapshothttp://m.tkk7.com/sandy/archive/2012/03/13/leveldb5.htmlTue, 13 Mar 2012 08:54:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/13/leveldb5.htmlhttp://m.tkk7.com/sandy/comments/371812.htmlhttp://m.tkk7.com/sandy/archive/2012/03/13/leveldb5.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/371812.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371812.html
先写一个测试程序来看看snapshot的用:(x)

#include <iostream>
#include 
"leveldb/db.h"

using namespace std;
using namespace leveldb;


int main() {
    DB 
*db ;
    Options op;
    op.create_if_missing 
= true;
    Status s 
= DB::Open(op,"/tmp/testdb",&db);

    
if(s.ok()){
        cout 
<< "create successfully" << endl;
        s 
= db->Put(WriteOptions(),"abcd","1234");
        
if(s.ok()){
            cout 
<< "put successfully" << endl;
            
string value;
            s 
= db->Get(ReadOptions(),"abcd",&value);
            
if(s.ok()){
                cout 
<< "get successfully,value:" << value << endl;
            }
        }
        
if(s.ok()){
            
string value;
            
const Snapshot * ss =db->GetSnapshot();
            ReadOptions rop;
            db
->Put(WriteOptions(),"abcd","123456");
            db
->Get(rop,"abcd",&value);
            
if(s.ok()){
                    cout 
<< "get successfully,value:" << value << endl;
            }
            rop.snapshot 
= ss;
            db
->Get(rop,"abcd",&value);
            
if(s.ok()){
                    cout 
<< "get from snapshot successfully,value:" << value << endl;
            }
            db
->ReleaseSnapshot(ss);
        }
    }
    delete db;
    
return 0;
}

E序q行的输出结果是Q?br />
create successfully
put successfully
get successfully,value:1234
get successfully,value:123456
get from snapshot successfully,value:1234

可以看出Q即使在数据更新后,我们仍然可以从snapshot中读到旧的数据?br />
下面我们来分析leveldb中snapshot的实现?br />
SequenceNumber(db/dbformat.h)
SequenceNumber是leveldb很重要的东西Q每ơ对数据库进行更新操作,都会(x)生成一个新的SequenceNumber,64bitsQ其中高8位ؓ(f)0Q可以跟key的类?8bits)q行合ƈ?4bits?/div>
typedef uint64_t SequenceNumber;

// We leave eight bits empty at the bottom so a type and sequence#
// can be packed together into 64-bits.
static const SequenceNumber kMaxSequenceNumber =
    ((0x1ull << 56) - 1);

SnapShot(db/snapshot.h),Q可以看出snapshot其实是一个sequence number
class SnapshotImpl : public Snapshot {
 
public:
  
//创徏后保持不?/span>
  SequenceNumber number_;  

 
private:
  friend 
class SnapshotList; 

  
//双向循环链表
  SnapshotImpl* prev_;
  SnapshotImpl
* next_;

  SnapshotList
* list_;                 // just for sanity checks
};

创徏snapshot:
const Snapshot* DBImpl::GetSnapshot() {
  MutexLock l(
&mutex_);
  
return snapshots_.New(versions_->LastSequence());
}

删除snapshot:
void DBImpl::ReleaseSnapshot(const Snapshot* s) {
  MutexLock l(
&mutex_);
  snapshots_.Delete(reinterpret_cast
<const SnapshotImpl*>(s));
}






2012-03-13 16:54 发表评论
]]>leveldb研究4- 数据文g的格式和生成http://m.tkk7.com/sandy/archive/2012/03/12/leveldb4.htmlMon, 12 Mar 2012 10:21:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/12/leveldb4.htmlhttp://m.tkk7.com/sandy/comments/371712.htmlhttp://m.tkk7.com/sandy/archive/2012/03/12/leveldb4.html#Feedback1http://m.tkk7.com/sandy/comments/commentRss/371712.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371712.html阅读全文

2012-03-12 18:21 发表评论
]]>
leveldb研究3-数据库日志文件格?/title><link>http://m.tkk7.com/sandy/archive/2012/03/09/leveldb3.html</link><dc:creator>明</dc:creator><author>明</author><pubDate>Fri, 09 Mar 2012 08:00:00 GMT</pubDate><guid>http://m.tkk7.com/sandy/archive/2012/03/09/leveldb3.html</guid><wfw:comment>http://m.tkk7.com/sandy/comments/371582.html</wfw:comment><comments>http://m.tkk7.com/sandy/archive/2012/03/09/leveldb3.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://m.tkk7.com/sandy/comments/commentRss/371582.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/sandy/services/trackbacks/371582.html</trackback:ping><description><![CDATA[     摘要: leveldb在每ơ数据库操作之前都会(x)把操作记录下来?主要实现在db\log_format.h,db\log_reader.h,db\log_reader.cc,db\log_write.h,db\log_write.cc中。我们来具体看看实现? 日志格式 db\log_format.h log是分块的Q每块ؓ(f)32K,每条记录的记录头?个字节,前四个ؓ(f)CRCQ然后是长度Q?个字节)(j)...  <a href='http://m.tkk7.com/sandy/archive/2012/03/09/leveldb3.html'>阅读全文</a><img src ="http://m.tkk7.com/sandy/aggbug/371582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/sandy/" target="_blank">明</a> 2012-03-09 16:00 <a href="http://m.tkk7.com/sandy/archive/2012/03/09/leveldb3.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>leveldb研究2- 存储分析http://m.tkk7.com/sandy/archive/2012/03/09/leveldb2.htmlFri, 09 Mar 2012 03:44:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/09/leveldb2.htmlhttp://m.tkk7.com/sandy/comments/371533.htmlhttp://m.tkk7.com/sandy/archive/2012/03/09/leveldb2.html#Feedback1http://m.tkk7.com/sandy/comments/commentRss/371533.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371533.html阅读全文

2012-03-09 11:44 发表评论
]]>
leveldb研究 - ~译/调试http://m.tkk7.com/sandy/archive/2012/03/08/leveldb1.htmlThu, 08 Mar 2012 03:44:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/08/leveldb1.htmlhttp://m.tkk7.com/sandy/comments/371423.htmlhttp://m.tkk7.com/sandy/archive/2012/03/08/leveldb1.html#Feedback1http://m.tkk7.com/sandy/comments/commentRss/371423.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371423.html
我的~译环境:ubuntu 32&g++ 4.6

1.安装gitq下载代?br />
sudo apt-get install git-core
git clone https:
//code.google.com/p/leveldb/

2. ~译leveldb

cd leveldb
.
/build_detect_platform
make

Z(jin)能够调试Q修改Makefile为debug mode(B模式)
OPT ?= -g2

~译后会(x)生成库文Ӟ(x)libleveldb.a

3. ~写试E序
ldbtest.cpp
#include <iostream>
#include 
"leveldb/db.h"

using namespace std;
using namespace leveldb;

int main() {
    DB 
*db ;
    Options op;
    op.create_if_missing 
= true;
    Status s 
= DB::Open(op,"/tmp/testdb",&db);

    
if(s.ok()){
        cout 
<< "create successfully" << endl;
        s 
= db->Put(WriteOptions(),"abcd","1234");
        
if(s.ok()){
            cout 
<< "put successfully" << endl;
            
string value;
            s 
= db->Get(ReadOptions(),"abcd",&value);
            
if(s.ok()){
                cout 
<< "get successfully,value:" << value << endl;
            }
            
else{
                cout 
<< "get failed" << endl;
            }
        }
        
else{
            cout 
<< "put failed" << endl;
        }
    }
    
else{
        cout 
<< "create failed" << endl;
    }
    delete db;
    
return 0;
}
注意link的时候需要加?lpthread.

q行后得到结果:(x)(Eclipse中运行)(j)



2012-03-08 11:44 发表评论
]]>
Learn From HBase/Bigtablehttp://m.tkk7.com/sandy/archive/2012/03/07/Learn_From_HBase.htmlWed, 07 Mar 2012 02:42:00 GMThttp://m.tkk7.com/sandy/archive/2012/03/07/Learn_From_HBase.htmlhttp://m.tkk7.com/sandy/comments/371379.htmlhttp://m.tkk7.com/sandy/archive/2012/03/07/Learn_From_HBase.html#Feedback0http://m.tkk7.com/sandy/comments/commentRss/371379.htmlhttp://m.tkk7.com/sandy/services/trackbacks/371379.html

学习(fn)软g有三个境界,W一个境界是?x)用它Q第二个境界是懂得背后的原理Q明白它的架构体p,W三个境界学?fn)他的所长,为我所用。研IHBase/BigTable架构和源码一D|间后Q我ȝ?jin)一些东西可以供我们在设计分布式pȝ借鉴使用?/p>

1. 使用可信ȝ分布式组件来搭徏自己的分布式pȝ?/strong>
?计一个可靠,健壮的分布式pȝ是比较困隄。我们知道,Z(jin)防止SPOF(Single Point Of Failure)问题Q我们要分散风险Q把数据攑֜多个nodes上面去,但是q样带来?jin)是数据的同步问题和版本问题Q解册个问题需要运用复杂的 Paxos协议Q系l的复杂度自然就升高?sh)(jin)。另外一个需要解决的问题是分布式锁和事g通知机制Q以?qing)全局信息׃nQ设计这些都需要大量的_֊和仔l的? I?/p>

HBase׃用考虑q些问题Q它把数据的同步和冗余问题(sh)l了(jin)Hadoop,把锁机制和全局׃n交给?jin)Zookeeper,q大大简化了(jin)HBase的设计?/p>

所以我们设计系l的时候,也要量利用q些可靠Q稳定的lg。目前比较流行和E_的有Q?br /> 分布式文件系l?nbsp;- HDFS
分布式锁和目?nbsp;- Zookeeper
~存 - MemCached
消息队列 - ActiveMQ

2.避免单点问题(SPOF)
设计分布式系l要时刻考虑到失败,不单是Y件可能失败,g也可能挂掉,所以我们系l里面就不能有不可替代的角色?/p>

HBase 使用Master Server来监控所有的Region Server,一旦其中的一台出现问题,在其上的Region会(x)被{Ud其他的Region ServerQ避免了(jin)服务中断。而Master Server也可以多台备选,一台挂掉之后,其他的备胎则?#8221;l承遗志“Q从而让整个pȝ得以生存?/p>

? HBase如何做到q个呢,一个是使用”?j)蟩机?#8221;Q即Region Server要主动定期向Master汇报状况Q另外一个是利用zookeeper里面?#8221;生命节点“Q每个server在启动后要在ZK里面注册Q一? q个server挂掉Q它在ZK里面的节点就?x)消失,监听q个节点的server׃(x)得到通知?/p>

3.利用不变性提高系l的吞吐?/strong>
我们知道Q很多进E?U程修改同一个东西的时候,我们需要锁机制来避免冲H。但是锁带来的问题是pȝ性能下降。如果对于一个只ȝ对象Q就不需要锁?jin)?/p>

HBase 在设计存储的时候考虑到这一点,最新的数据是放在memory里面Q以提高性能。但是memory是有限的Q我们不可能让数据一直放在memory里面Q? 所以我们需要定时把q些数据写到HDFS/盘?sh)面。一U设计是写到一个可修改的大文g中去Q这样对q个文g的读写就需要加锁了(jin)。HBase是每ơ都写到 一个新的文件中Q一旦文件创建后Q这个文件将不能被修改,是所谓的create-one-read-many。当然这样也有一个问题,是旉长了(jin)Q会(x) 有很多的文Ӟ每次查找Q需要查找这所有的文gQ降低了(jin)pȝ的性能QHBase?x)定时的合ƈq些文件生成一个大文g?/p>

4.利用索引块提高文件的查询速度
HBase的存储文?HFile)是用来存储很多排序后的Key-Value的,如何设计一U支持快速随机查询和压羃的文件是一个有意思的话题?/p>

HFile 在文件的N增加?jin)?ch)引块Q但是不可能对Q何一个rowkey都做索引Q这L(fng)话烦(ch)引块?x)很大,而且也不利于压羃。HFile的做法是定义一个Data Block的大,q样把数据划分?jin)一个一个的BlockQ烦(ch)引只针对q些block做,Block是可以被压羃的。当查询一个rowkey的时候,? 果没有cache的话Q首先用二分法定位到具体的blockQ然后再解压Q遍历查询具体的key?/p>

HFileq样的设计兼了(jin)速度和文件大的q?/p>

5.自定义RPC机制提供更大的灵zL?/strong>
HBase/Hadoop 都没有利用标准的Javaq程调用规范RMI,而是自己搞了(jin)一套。这样做的好处有几点Q一是减网l流量,我们知道Qjava RMI使用?jin)java serlizable来传递参敎ͼjava序列化有很多无关的类信息Q都占用不少的空_(d)而且q会(x)带来对java版本的依赖。二是带来更大的灉|性,你可 以在其中加入版本(g)查,权限认证{?/p>

? HBase是怎么设计q个RPC呢?首先它定义了(jin)一个writable接口Q来代替java序列化,实现q个接口q于告诉HBaseQ怎么把这个对象写 到RPC中厅R用RPC的时候,需要先写一个服务器端和客户端共用的interface,q个interface必须l承 VersionedProtocol来处理版本问?nbsp;。HBase利用Java的动态反机?Proxy.newProxyInstance)来生成代 理对象,q样当Client调用代理对象的时候,Client׃(x)把参数打包,发送到服务器端Q然后等待返回结果。服务器?x)根据interface查找? 具体的实现的对象Q调用该对象的方法来执行q程调用。详l的做法可以参考HBase/Hadoop的源码?/p>

6.内嵌W(xu)eb Server增强pȝ的透明?/strong>
当一个后台进E启动之后,我们如何?jin)解q个q程的内部状态呢Q传l方法是通过q程理器或者Debug log来看q程的情况,但是q些信息很有限?/p>

HBase利用jetty在进E内部启动了(jin)一个web serverQ就可以x(chng)的显CZ些系l内部的信息Q非常的方便?/p>

? 用Jetty支持jsp非常的容易,下面是一个示例的代码。注意的是,需要把jasper-runtime-5.5.12.jar,jasper- compiler-5.5.12.jar,jasper-compiler-jdt-5.5.12.jar,jsp-2.1.jar,jsp-api- 2.1.jar{jar包放在classpath里面Q否则会(x)出现面解析错误?/p>

server = new Server(port);

server.setSendServerVersion(false);
server.setSendDateHeader(false);
server.setStopAtShutdown(true);

WebAppContext wac = new WebAppContext();
wac.setContextPath("/");
wac.setWar("./webapps/job");
server.setHandler(wac);
server.setStopAtShutdown(true);



2012-03-07 10:42 发表评论
]]>
վ֩ģ壺 Ƶ߲| ؼaaaaaaaaaëƬƵ| AVպƷһ| 91˿߹ۿ | Ƶվ| AV뾫Ʒ| ëƬƵ| 99re99reƵֻ| ޹++ۺ| Ʒһʽֱ| Ļ| վѹۿ| þ޹վ| ͼƬĻ| ɫƵ߹ۿ| ޳avƬ߹ۿ| ޾ƷƵ| ŷɫŷ| avۺר| ʵŹ| ޵һվ| wwwѹۿվ| ƷŮͬһѲ| ˳վ߲vr| ޹ۺϾƷһ߲| ҹӰѹۿ| ĻƵƷһ| һƵ| ͼƬС˵| gayƬgvվ| պƷ3| 99þùۺϾƷ| ۺɫͼƬ| kkk4444߹ۿ| ˳վɫ7799| AVɫ߹ۿ| av| ˳aƬվ| ɫͷۺƵ| 777777| 99鶹þþùƷ |