github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/leveldb/session_util.go (about)

     1  // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
     2  // All rights reserved.
     3  //
     4  // Use of this source code is governed by a BSD-style license that can be
     5  // found in the LICENSE file.
     6  
     7  package leveldb
     8  
     9  import (
    10  	"fmt"
    11  	"sync/atomic"
    12  
    13  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/journal"
    14  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/storage"
    15  )
    16  
    17  // Logging.
    18  
    19  type dropper struct {
    20  	s  *session
    21  	fd storage.FileDesc
    22  }
    23  
    24  func (d dropper) Drop(err error) {
    25  	if e, ok := err.(*journal.ErrCorrupted); ok {
    26  		d.s.logf("journal@drop %s-%d S·%s %q", d.fd.Type, d.fd.Num, shortenb(e.Size), e.Reason)
    27  	} else {
    28  		d.s.logf("journal@drop %s-%d %q", d.fd.Type, d.fd.Num, err)
    29  	}
    30  }
    31  
    32  func (s *session) log(v ...interface{})                 { s.stor.Log(fmt.Sprint(v...)) }
    33  func (s *session) logf(format string, v ...interface{}) { s.stor.Log(fmt.Sprintf(format, v...)) }
    34  
    35  // File utils.
    36  
    37  func (s *session) newTemp() storage.FileDesc {
    38  	num := atomic.AddInt64(&s.stTempFileNum, 1) - 1
    39  	return storage.FileDesc{storage.TypeTemp, num}
    40  }
    41  
    42  // Session state.
    43  
    44  // Get current version. This will incr version ref, must call
    45  // version.release (exactly once) after use.
    46  func (s *session) version() *version {
    47  	s.vmu.Lock()
    48  	defer s.vmu.Unlock()
    49  	s.stVersion.ref++
    50  	return s.stVersion
    51  }
    52  
    53  // Set current version to v.
    54  func (s *session) setVersion(v *version) {
    55  	s.vmu.Lock()
    56  	v.ref = 1 // Holds by session.
    57  	if old := s.stVersion; old != nil {
    58  		v.ref++ // Holds by old version.
    59  		old.next = v
    60  		old.releaseNB()
    61  	}
    62  	s.stVersion = v
    63  	s.vmu.Unlock()
    64  }
    65  
    66  // Get current unused file number.
    67  func (s *session) nextFileNum() int64 {
    68  	return atomic.LoadInt64(&s.stNextFileNum)
    69  }
    70  
    71  // Set current unused file number to num.
    72  func (s *session) setNextFileNum(num int64) {
    73  	atomic.StoreInt64(&s.stNextFileNum, num)
    74  }
    75  
    76  // Mark file number as used.
    77  func (s *session) markFileNum(num int64) {
    78  	nextFileNum := num + 1
    79  	for {
    80  		old, x := s.stNextFileNum, nextFileNum
    81  		if old > x {
    82  			x = old
    83  		}
    84  		if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
    85  			break
    86  		}
    87  	}
    88  }
    89  
    90  // Allocate a file number.
    91  func (s *session) allocFileNum() int64 {
    92  	return atomic.AddInt64(&s.stNextFileNum, 1) - 1
    93  }
    94  
    95  // Reuse given file number.
    96  func (s *session) reuseFileNum(num int64) {
    97  	for {
    98  		old, x := s.stNextFileNum, num
    99  		if old != x+1 {
   100  			x = old
   101  		}
   102  		if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
   103  			break
   104  		}
   105  	}
   106  }
   107  
   108  // Set compaction ptr at given level; need external synchronization.
   109  func (s *session) setCompPtr(level int, ik internalKey) {
   110  	if level >= len(s.stCompPtrs) {
   111  		newCompPtrs := make([]internalKey, level+1)
   112  		copy(newCompPtrs, s.stCompPtrs)
   113  		s.stCompPtrs = newCompPtrs
   114  	}
   115  	s.stCompPtrs[level] = append(internalKey{}, ik...)
   116  }
   117  
   118  // Get compaction ptr at given level; need external synchronization.
   119  func (s *session) getCompPtr(level int) internalKey {
   120  	if level >= len(s.stCompPtrs) {
   121  		return nil
   122  	}
   123  	return s.stCompPtrs[level]
   124  }
   125  
   126  // Manifest related utils.
   127  
   128  // Fill given session record obj with current states; need external
   129  // synchronization.
   130  func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
   131  	r.setNextFileNum(s.nextFileNum())
   132  
   133  	if snapshot {
   134  		if !r.has(recJournalNum) {
   135  			r.setJournalNum(s.stJournalNum)
   136  		}
   137  
   138  		if !r.has(recSeqNum) {
   139  			r.setSeqNum(s.stSeqNum)
   140  		}
   141  
   142  		for level, ik := range s.stCompPtrs {
   143  			if ik != nil {
   144  				r.addCompPtr(level, ik)
   145  			}
   146  		}
   147  
   148  		r.setComparer(s.icmp.uName())
   149  	}
   150  }
   151  
   152  // Mark if record has been committed, this will update session state;
   153  // need external synchronization.
   154  func (s *session) recordCommited(rec *sessionRecord) {
   155  	if rec.has(recJournalNum) {
   156  		s.stJournalNum = rec.journalNum
   157  	}
   158  
   159  	if rec.has(recPrevJournalNum) {
   160  		s.stPrevJournalNum = rec.prevJournalNum
   161  	}
   162  
   163  	if rec.has(recSeqNum) {
   164  		s.stSeqNum = rec.seqNum
   165  	}
   166  
   167  	for _, r := range rec.compPtrs {
   168  		s.setCompPtr(r.level, internalKey(r.ikey))
   169  	}
   170  }
   171  
   172  // Create a new manifest file; need external synchronization.
   173  func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
   174  	fd := storage.FileDesc{storage.TypeManifest, s.allocFileNum()}
   175  	writer, err := s.stor.Create(fd)
   176  	if err != nil {
   177  		return
   178  	}
   179  	jw := journal.NewWriter(writer)
   180  
   181  	if v == nil {
   182  		v = s.version()
   183  		defer v.release()
   184  	}
   185  	if rec == nil {
   186  		rec = &sessionRecord{}
   187  	}
   188  	s.fillRecord(rec, true)
   189  	v.fillRecord(rec)
   190  
   191  	defer func() {
   192  		if err == nil {
   193  			s.recordCommited(rec)
   194  			if s.manifest != nil {
   195  				s.manifest.Close()
   196  			}
   197  			if s.manifestWriter != nil {
   198  				s.manifestWriter.Close()
   199  			}
   200  			if !s.manifestFd.Nil() {
   201  				s.stor.Remove(s.manifestFd)
   202  			}
   203  			s.manifestFd = fd
   204  			s.manifestWriter = writer
   205  			s.manifest = jw
   206  		} else {
   207  			writer.Close()
   208  			s.stor.Remove(fd)
   209  			s.reuseFileNum(fd.Num)
   210  		}
   211  	}()
   212  
   213  	w, err := jw.Next()
   214  	if err != nil {
   215  		return
   216  	}
   217  	err = rec.encode(w)
   218  	if err != nil {
   219  		return
   220  	}
   221  	err = jw.Flush()
   222  	if err != nil {
   223  		return
   224  	}
   225  	err = s.stor.SetMeta(fd)
   226  	return
   227  }
   228  
   229  // Flush record to disk.
   230  func (s *session) flushManifest(rec *sessionRecord) (err error) {
   231  	s.fillRecord(rec, false)
   232  	w, err := s.manifest.Next()
   233  	if err != nil {
   234  		return
   235  	}
   236  	err = rec.encode(w)
   237  	if err != nil {
   238  		return
   239  	}
   240  	err = s.manifest.Flush()
   241  	if err != nil {
   242  		return
   243  	}
   244  	if !s.o.GetNoSync() {
   245  		err = s.manifestWriter.Sync()
   246  		if err != nil {
   247  			return
   248  		}
   249  	}
   250  	s.recordCommited(rec)
   251  	return
   252  }