code: func (db *db) begin(writable bool) (*transaction, error) {
  	// Whenever a new writable transaction is started, grab the write lock
  	// to ensure only a single write transaction can be active at the same
  	// time.  This lock will not be released until the transaction is
  	// closed (via Rollback or Commit).
  	if writable {
  		db.writeLock.Lock()
  	}
  
  	// Whenever a new transaction is started, grab a read lock against the
  	// database to ensure Close will wait for the transaction to finish.
  	// This lock will not be released until the transaction is closed (via
  	// Rollback or Commit).
  	db.closeLock.RLock()
  	if db.closed {
  		db.closeLock.RUnlock()
  		if writable {
  			db.writeLock.Unlock()
  		}
  		return nil, makeDbErr(database.ErrDbNotOpen, errDbNotOpenStr,
  			nil)
  	}
  
  	// Grab a snapshot of the database cache (which in turn also handles the
  	// underlying database).
  	snapshot, err := db.cache.Snapshot()
  	if err != nil {
  		db.closeLock.RUnlock()
  		if writable {
  			db.writeLock.Unlock()
  		}
  
  		return nil, err
  	}
  
  	// The metadata and block index buckets are internal-only buckets, so
  	// they have defined IDs.
  	tx := &transaction{
  		writable:      writable,
  		db:            db,
  		snapshot:      snapshot,
  		pendingKeys:   treap.NewMutable(),
  		pendingRemove: treap.NewMutable(),
  	}
  	tx.metaBucket = &bucket{tx: tx, id: metadataBucketID}
  	tx.blockIdxBucket = &bucket{tx: tx, id: blockIdxBucketID}
  	return tx, nil
  }
docs: // begin is the implementation function for the Begin database method.  See its
  // documentation for more details.
  //
  // This function is only separate because it returns the internal transaction
  // which is used by the managed transaction code while the database method
  // returns the interface.