示例#1
0
// skews returns clock skew information for all writers recorded in the
// document, given that the document was read between the supplied local
// times. It will return an error if the clock document is not valid, or
// if the times don't make sense.
func (doc clockDoc) skews(beginning, end time.Time) (map[string]Skew, error) {
	if err := doc.validate(); err != nil {
		return nil, errors.Trace(err)
	}
	// beginning is expected to be earlier than end.
	// If it isn't, it could be ntp rolling the clock back slowly, so we add
	// a little wiggle room here.
	if end.Before(beginning) {
		// A later time, subtract an earlier time will give a positive duration.
		difference := beginning.Sub(end)
		if difference > 10*time.Millisecond {
			return nil, errors.Errorf("end of read window preceded beginning (%s)", difference)

		}
		beginning = end
	}
	skews := make(map[string]Skew)
	for writer, written := range doc.Writers {
		skews[writer] = Skew{
			LastWrite: toTime(written),
			Beginning: beginning,
			End:       end,
		}
	}
	return skews, nil
}
示例#2
0
func (r *Rrd) Update(timestamp time.Time, values []string) error {
	if timestamp.Before(r.LastUpdate) {
		return errors.Errorf("illegal attempt to update using time %s when last update time is %s (minimum one second step)", timestamp.String(), r.LastUpdate.String())
	}

	elapsed := r.calculateElapsedSteps(timestamp)

	newPdps, err := r.calculatePdpPreps(elapsed.Interval, values)
	if err != nil {
		return err
	}

	if elapsed.Steps == 0 {
		r.simpleUpdate(newPdps, elapsed.Interval)
	} else {
		pdpTemp := r.processAllPdp(newPdps, elapsed)
		rraStepCounts := r.updateAllCdpPreps(pdpTemp, elapsed)
		r.updateAberrantCdps(pdpTemp, elapsed)
		r.writeToRras(rraStepCounts)
		for i, rra := range r.Rras {
			if err := r.Store.StoreRraParams(i, rra); err != nil {
				return err
			}
		}
	}

	return r.writeChanges(timestamp)
}
示例#3
0
// Returns wheter the Timing is active at the specified time
func (rit *RITiming) IsActiveAt(t time.Time) bool {
	// check for years
	if len(rit.Years) > 0 && !rit.Years.Contains(t.Year()) {
		return false
	}
	// check for months
	if len(rit.Months) > 0 && !rit.Months.Contains(t.Month()) {
		return false
	}
	// check for month days
	if len(rit.MonthDays) > 0 && !rit.MonthDays.Contains(t.Day()) {
		return false
	}
	// check for weekdays
	if len(rit.WeekDays) > 0 && !rit.WeekDays.Contains(t.Weekday()) {
		return false
	}
	//log.Print("Time: ", t)

	//log.Print("Left Margin: ", rit.getLeftMargin(t))
	// check for start hour
	if t.Before(rit.getLeftMargin(t)) {
		return false
	}

	//log.Print("Right Margin: ", rit.getRightMargin(t))
	// check for end hour
	if t.After(rit.getRightMargin(t)) {
		return false
	}
	return true
}
示例#4
0
// Locate the event in this object that is unrelated to the alert event,
// and is closest to it based on the timestamp
func (ad *alertDetailsBranch) addPreviousEvent(o *object, branchID string) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("addPreviousEvent() -> %v", e)
		}
	}()

	var res *objectResult
	var latest time.Time
	for i := range o.Results {
		if o.Results[i].BranchID == branchID {
			continue
		} else if o.Results[i].CollapseBranch == branchID {
			continue
		}
		if latest.Before(o.Results[i].Timestamp) {
			res = &o.Results[i]
		}
	}
	if res == nil {
		return nil
	}

	ad.PrevLocality = res.Locality
	ad.PrevLatitude = res.Latitude
	ad.PrevLongitude = res.Longitude
	ad.PrevTimestamp = res.Timestamp
	ad.PrevDistance = kmBetweenTwoPoints(ad.Latitude, ad.Longitude,
		ad.PrevLatitude, ad.PrevLongitude)
	return nil
}
示例#5
0
// ActiveAt says whether the given time is
// wihtin the schedule of this Day schedule.
func (d *Day) ActiveAt(t time.Time) bool {
	if loc, err := d.GetLocation(); loc != nil && err == nil {
		t = t.In(loc)
	}
	start, stop := d.Times(t)
	return t.After(start) && t.Before(stop)
}
示例#6
0
// advance cycles the buckets at each level until the latest bucket in
// each level can hold the time specified.
func (ts *timeSeries) advance(t time.Time) {
	if !t.After(ts.levels[0].end) {
		return
	}
	for i := 0; i < len(ts.levels); i++ {
		level := ts.levels[i]
		if !level.end.Before(t) {
			break
		}

		// If the time is sufficiently far, just clear the level and advance
		// directly.
		if !t.Before(level.end.Add(level.size * time.Duration(ts.numBuckets))) {
			for _, b := range level.buckets {
				ts.resetObservation(b)
			}
			level.end = time.Unix(0, (t.UnixNano()/level.size.Nanoseconds())*level.size.Nanoseconds())
		}

		for t.After(level.end) {
			level.end = level.end.Add(level.size)
			level.newest = level.oldest
			level.oldest = (level.oldest + 1) % ts.numBuckets
			ts.resetObservation(level.buckets[level.newest])
		}

		t = level.end
	}
}
示例#7
0
func LoadPerf(fName string, since, until time.Time) ([]PerfLogEntry, error) {
	fIn, err := os.Open(fName)
	if err != nil {
		return nil, err
	}
	defer fIn.Close()

	dec := json.NewDecoder(fIn)
	var result []PerfLogEntry
	for {
		var entry PerfLogEntry
		err = dec.Decode(&entry)
		if err != nil {
			if strings.Contains(err.Error(), "EOF") {
				break
			} else {
				return nil, fmt.Errorf("Decode error: %v", err)
			}
		} else {
			if !since.Equal(time.Time{}) && since.After(entry.Timestamp) {
				continue
			}
			if !until.Equal(time.Time{}) && until.Before(entry.Timestamp) {
				continue
			}
			result = append(result, entry)
		}
	}
	return result, nil
}
示例#8
0
func (rm *realManager) housekeep(start, end time.Time) {
	if !start.Before(end) {
		glog.Warningf("Wrong time provided to housekeep start:%s end: %s", start, end)
		return
	}

	select {
	case <-rm.housekeepSemaphoreChan:
		// ok, good to go

	case <-time.After(rm.housekeepTimeout):
		glog.Warningf("Spent too long waiting for housekeeping to start")
		return
	}

	go func(rm *realManager) {
		// should always give back the semaphore
		defer func() { rm.housekeepSemaphoreChan <- struct{}{} }()
		data := rm.source.ScrapeMetrics(start, end)

		for _, p := range rm.processors {
			newData, err := process(p, data)
			if err == nil {
				data = newData
			} else {
				glog.Errorf("Error in processor: %v", err)
				return
			}
		}

		// Export data to sinks
		rm.sink.ExportData(data)

	}(rm)
}
示例#9
0
// Determine whether we should roll the log file. Must be in lock already.
func (a *fileAppender) shouldRoll(tstamp time.Time) bool {
	if a.rollFrequency == RollNone {
		return false
	} else {
		return !tstamp.Before(a.nextRollTime)
	}
}
示例#10
0
文件: shift.go 项目: jaffee/sked
func (i *Interval) SetStart(t time.Time) error {
	if !t.Before(i.End()) {
		return errors.New("Start must be before end.")
	}
	i.StartTime = t
	return nil
}
示例#11
0
文件: bench.go 项目: jyzhe/beehive
func launchWorker(c *client.Client, w workload, timeout time.Duration,
	start chan struct{}, resch chan result) {

	<-start

	call := make(chan client.Response, len(w.enqs))
	reqStart := make(map[server.ReqID]time.Time)
	reqEnd := make(map[server.ReqID]time.Time)

	var minStart time.Time
	done := make(chan struct{})
	go func() {
		for i, e := range w.enqs {
			now := time.Now()
			if i == 0 {
				minStart = now
			}
			req, _ := c.GoEnQ(string(e.Queue), e.Body, call)
			reqStart[req] = now
		}
		close(done)
	}()

	res := result{
		// TODO(soheil): implement deques as well.
		size: uint64(len(w.enqs)), //+ len(w.deqs),
	}
	var to <-chan time.Time
	if timeout != 0 {
		to = time.After(timeout)
	}

loop:
	for i := 0; i < len(w.enqs); i++ {
		select {
		case response := <-call:
			if response.Error != nil {
				continue
			}
			reqEnd[response.ID] = time.Now()
			res.reqs++
		case <-to:
			break loop
		}
	}

	<-done

	var maxEnd time.Time
	for req, end := range reqEnd {
		if maxEnd.Before(end) {
			maxEnd = end
		}
		d := end.Sub(reqStart[req])
		res.enqDurs = append(res.enqDurs, d)
	}
	res.start = minStart
	res.end = maxEnd
	resch <- res
}
示例#12
0
文件: holiday.go 项目: igungor/ilber
func in(date, start, end time.Time) bool {
	if date.Equal(start) || date.Equal(end) {
		return true
	}

	return date.After(start) && date.Before(end)
}
示例#13
0
func (reqs Requests) GetQuery() url.Values {
	query := make(url.Values)
	var from, until time.Time

	for _, r := range reqs {
		query.Add("target", r.Key)
		if from.IsZero() {
			from = r.From
		} else if from.After(r.From) {
			from = r.From
		}
		if until.IsZero() {
			until = r.Until
		} else if until.Before(r.Until) {
			until = r.Until
		}
	}
	if !from.IsZero() {
		query.Add("from", strconv.FormatInt(from.Unix(), 10))
	}
	if !until.IsZero() {
		query.Add("until", strconv.FormatInt(until.Unix(), 10))
	}
	return query
}
示例#14
0
func posts(url string, lastModified time.Time) []Post {
	doc, err := goquery.NewDocument(url)
	errNotNilToPanic(err)
	lastPage := 0
	doc.Find("ul").EachWithBreak(func(_ int, s *goquery.Selection) bool {
		if class, exist := s.Attr("class"); exist && class == "pagination" {
			if href, exist := s.Find("li").Find("a").Last().Attr("href"); exist {
				reg := regexp.MustCompile(".*page_num=([0-9]+)$")
				if m := reg.FindStringSubmatch(href); len(m) > 1 {
					lastPage, _ = strconv.Atoi(m[1])
				}
			}
			return false
		}
		return true
	})
	pList := []Post{}
	for page := 1; page <= lastPage; page++ {
		doc, err := goquery.NewDocument(url + "?comment_order=DESC&page_num=" + strconv.Itoa(page))
		errNotNilToPanic(err)
		doc.Find("div").EachWithBreak(func(_ int, s *goquery.Selection) bool {
			if class, exist := s.Attr("class"); exist && class == "post-sla" {
				p := post(s)
				if !lastModified.Before(p.postDate) {
					return false
				}
				pList = append(pList, p)
			}
			return true
		})
	}
	return pList
}
示例#15
0
文件: chtimes.go 项目: CNDonny/scope
// Chtimes changes the access time and modified time of a file at the given path
func Chtimes(name string, atime time.Time, mtime time.Time) error {
	unixMinTime := time.Unix(0, 0)
	unixMaxTime := maxTime

	// If the modified time is prior to the Unix Epoch, or after the
	// end of Unix Time, os.Chtimes has undefined behavior
	// default to Unix Epoch in this case, just in case

	if atime.Before(unixMinTime) || atime.After(unixMaxTime) {
		atime = unixMinTime
	}

	if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) {
		mtime = unixMinTime
	}

	if err := os.Chtimes(name, atime, mtime); err != nil {
		return err
	}

	// Take platform specific action for setting create time.
	if err := setCTime(name, mtime); err != nil {
		return err
	}

	return nil
}
示例#16
0
func SubSeries(ts *TimeSeries, start, end time.Time) *TimeSeries {
	if ts == nil {
		return nil
	}

	if start.IsZero() || start.Before(ts.Start()) {
		start = ts.Start()
	}
	if end.IsZero() || ts.End().Before(end) {
		end = ts.End()
	}
	key := fmt.Sprintf("SubSeries(%s,%s)(%s)", start.Format(time.RFC3339), end.Format(time.RFC3339), ts.Key())
	step := ts.Step()

	newTs, err := NewTimeSeriesOfTimeRange(key, start, end, step, math.NaN())
	if err != nil {
		return nil
	}

	for cursor := start; cursor.Before(end); cursor = cursor.Add(step) {
		v, _ := ts.GetAt(cursor)
		newTs.SetAt(cursor, v)
		if int(step) == 0 {
			break
		}
	}
	return newTs
}
示例#17
0
文件: user.go 项目: niemeyer/snapd
// ValidAt returns whether the system-user is valid at 'when' time.
func (su *SystemUser) ValidAt(when time.Time) bool {
	valid := when.After(su.since) || when.Equal(su.since)
	if valid {
		valid = when.Before(su.until)
	}
	return valid
}
示例#18
0
文件: utils.go 项目: catanm/gms
func LinkGpsToImages(track m.Track) {
	var possibleImages []m.Image
	m.GetDB("Image").Find(bson.M{"date": bson.M{"$lte": track.MaxDate, "$gte": track.MinDate}, "user": track.User}).All(&possibleImages)

	if len(possibleImages) == 0 {
		return
	}

	var best m.Coordinate

	var before time.Time
	var after time.Time

	for i := 0; i < len(possibleImages); i++ {
		before = possibleImages[i].Date.Add(time.Duration(-10 * time.Second))
		after = possibleImages[i].Date.Add(time.Duration(10 * time.Second))

		for j := 0; j < len(track.Coordinates); j++ {
			if before.Before(track.Coordinates[j].Date) && after.After(track.Coordinates[j].Date) {
				best = track.Coordinates[j]
				break
			}
		}
		if best.Lat != "" && best.Lon != "" {
			possibleImages[i].Lat = best.Lat
			possibleImages[i].Lon = best.Lon
			err := m.GetDB("Image").UpdateId(possibleImages[i].Id, possibleImages[i])
			if err != nil {
				log.Error("LinkGpdToImages, update, " + err.Error())
			}
		}
	}
}
示例#19
0
// ComputeRange computes a specified number of values into a slice using
// the observations recorded over the specified time period. The return
// values are approximate if the start or finish times don't fall on the
// bucket boundaries at the same level or if the number of buckets spanning
// the range is not an integral multiple of num.
func (ts *timeSeries) ComputeRange(start, finish time.Time, num int) []Observable {
	if start.After(finish) {
		log.Printf("timeseries: start > finish, %v>%v", start, finish)
		return nil
	}

	if num < 0 {
		log.Printf("timeseries: num < 0, %v", num)
		return nil
	}

	results := make([]Observable, num)

	for _, l := range ts.levels {
		if !start.Before(l.end.Add(-l.size * time.Duration(ts.numBuckets))) {
			ts.extract(l, start, finish, num, results)
			return results
		}
	}

	// Failed to find a level that covers the desired range.  So just
	// extract from the last level, even if it doesn't cover the entire
	// desired range.
	ts.extract(ts.levels[len(ts.levels)-1], start, finish, num, results)

	return results
}
示例#20
0
文件: filter.go 项目: kpabba/rclone
// Include returns whether this object should be included into the
// sync or not
func (f *Filter) Include(remote string, size int64, modTime time.Time) bool {
	// filesFrom takes precedence
	if f.files != nil {
		_, include := f.files[remote]
		return include
	}
	if !f.ModTimeFrom.IsZero() && modTime.Before(f.ModTimeFrom) {
		return false
	}
	if !f.ModTimeTo.IsZero() && modTime.After(f.ModTimeTo) {
		return false
	}
	if f.MinSize != 0 && size < f.MinSize {
		return false
	}
	if f.MaxSize != 0 && size > f.MaxSize {
		return false
	}
	for _, rule := range f.rules {
		if rule.Match(remote) {
			return rule.Include
		}
	}
	return true
}
示例#21
0
func (s *state) handleElectionTimers(now time.Time) {
	for _, g := range s.groups {
		if !now.Before(g.electionDeadline) {
			s.becomeCandidate(g)
		}
	}
}
示例#22
0
func TestAfterAuthFail_Reset(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	var old, current time.Time
	var ok bool

	ctx := ab.NewContext()
	storer := mocks.NewMockStorer()
	lock := Lock{ab}
	ab.LockWindow = 30 * time.Minute
	ab.Storer = storer

	old = time.Now().UTC().Add(-time.Hour)

	email := "*****@*****.**"
	ctx.User = map[string]interface{}{
		ab.PrimaryID:       email,
		StoreAttemptNumber: int64(2),
		StoreAttemptTime:   old,
		StoreLocked:        old,
	}

	lock.afterAuthFail(ctx)
	if val := storer.Users[email][StoreAttemptNumber].(int64); val != int64(0) {
		t.Error("StoreAttemptNumber set incorrectly:", val)
	}
	if current, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok || current.Before(old) {
		t.Error("StoreAttemptTime not set correctly.")
	}
	if locked := storer.Users[email][StoreLocked].(time.Time); locked.After(time.Now()) {
		t.Error("StoreLocked not set correctly:", locked)
	}
}
func TestPriorityQueue_order_Time(t *testing.T) {
	pq := NewPriorityQueue(Less(func(x, y interface{}) bool {
		return x.(time.Time).Before(y.(time.Time))
	}), 10)

	//Populate the priority queue with random times
	var src rand.Source = rand.NewSource(0)
	var r *rand.Rand = rand.New(src)
	for i := 0; i < 10; i++ {
		assert.True(
			t,
			pq.Length() == i,
			"pq.Length() = %d; want %d", pq.Length(), i,
		)
		pq.Insert(time.Now().Add(time.Hour * time.Duration(r.Int())))
	}
	var prev time.Time = pq.PopTop().(time.Time)
	var next time.Time
	for pq.Length() > 0 {
		next = pq.PopTop().(time.Time)
		assert.True(
			t,
			prev.Before(next),
			"%s sorted before %s; want %s sorted after %s", prev, next, prev, next,
		)
	}
}
示例#24
0
文件: gametime.go 项目: gdelaney/WMS
func isGametime(t time.Time) bool {
	var start, end time.Time
	year := t.Year()
	month := t.Month()
	day := t.Day()
	hour := t.Hour()
	loc := t.Location()
	switch t.Weekday() {
	case time.Monday, time.Tuesday, time.Wednesday, time.Thursday:
		start = time.Date(year, month, day, 20, 0, 0, 0, loc)
		end = time.Date(year, month, day, 23, 59, 59, 999999999, loc)
	case time.Friday:
		start = time.Date(year, month, day, 19, 0, 0, 0, loc)
		end = time.Date(year, month, day+1, 2, 59, 59, 999999999, loc)
	case time.Saturday:
		if hour < 3 {
			start = time.Date(year, month, day-1, 23, 59, 59, 999999999, loc)
			end = time.Date(year, month, day, 2, 59, 59, 999999999, loc)
		} else {
			start = time.Date(year, month, day, 15, 0, 0, 0, loc)
			end = time.Date(year, month, day+1, 2, 59, 59, 999999999, loc)
		}
	case time.Sunday:
		if hour < 3 {
			start = time.Date(year, month, day-1, 23, 59, 59, 999999999, loc)
			end = time.Date(year, month, day, 2, 59, 59, 999999999, loc)
		} else {
			start = time.Date(year, month, day, 17, 0, 0, 0, loc)
			end = time.Date(year, month, day, 23, 59, 59, 999999999, loc)
		}
	}
	return (t.After(start) && t.Before(end))
}
示例#25
0
文件: date.go 项目: aquilax/ledger
func getDateBoundaries(per Period, start, end time.Time) []time.Time {
	var incMonth, incYear int
	var periodStart time.Time

	switch per {
	case PeriodMonth:
		incMonth = 1
		periodStart = time.Date(start.Year(), start.Month(), 1, 0, 0, 0, 0, time.UTC)
	case PeriodQuarter:
		incMonth = 3
		switch start.Month() {
		case time.January, time.February, time.March:
			periodStart = time.Date(start.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
		case time.April, time.May, time.June:
			periodStart = time.Date(start.Year(), time.April, 1, 0, 0, 0, 0, time.UTC)
		case time.July, time.August, time.September:
			periodStart = time.Date(start.Year(), time.July, 1, 0, 0, 0, 0, time.UTC)
		default:
			periodStart = time.Date(start.Year(), time.October, 1, 0, 0, 0, 0, time.UTC)
		}
	case PeriodYear:
		incYear = 1
		periodStart = time.Date(start.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
	}

	boundaries := []time.Time{periodStart}
	for periodStart.Before(end) {
		periodStart = periodStart.AddDate(incYear, incMonth, 0)
		boundaries = append(boundaries, periodStart)
	}

	return boundaries
}
示例#26
0
func (this Session) is_actual(time_now time.Time) bool {
	this.mu.RLock()
	actual := time_now.Before(this.last_time.Add(maxlifetime))
	this.mu.RUnlock()

	return actual
}
示例#27
0
// isKeyValidAt returns whether the account key is valid at 'when' time.
func (ak *AccountKey) isKeyValidAt(when time.Time) bool {
	valid := when.After(ak.since) || when.Equal(ak.since)
	if valid && !ak.until.IsZero() {
		valid = when.Before(ak.until)
	}
	return valid
}
示例#28
0
文件: ec2.go 项目: tychoish/evergreen
// CostForDuration returns the cost of running a host between the given start and end times
func (cloudManager *EC2Manager) CostForDuration(h *host.Host, start, end time.Time) (float64, error) {
	// sanity check
	if end.Before(start) || util.IsZeroTime(start) || util.IsZeroTime(end) {
		return 0, fmt.Errorf("task timing data is malformed")
	}
	// grab instance details from EC2
	ec2Handle := getUSEast(*cloudManager.awsCredentials)
	instance, err := getInstanceInfo(ec2Handle, h.Id)
	if err != nil {
		return 0, err
	}
	os := osLinux
	if strings.Contains(h.Distro.Arch, "windows") {
		os = osWindows
	}
	dur := end.Sub(start)
	region := azToRegion(instance.AvailabilityZone)
	iType := instance.InstanceType

	ebsCost, err := blockDeviceCosts(ec2Handle, instance.BlockDevices, dur)
	if err != nil {
		return 0, fmt.Errorf("calculating block device costs: %v", err)
	}
	hostCost, err := onDemandCost(&pkgOnDemandPriceFetcher, os, iType, region, dur)
	if err != nil {
		return 0, err
	}
	return hostCost + ebsCost, nil
}
示例#29
0
文件: server.go 项目: dnaeon/etcd
func (s *EtcdServer) parseProposeCtxErr(err error, start time.Time) error {
	switch err {
	case context.Canceled:
		return ErrCanceled
	case context.DeadlineExceeded:
		curLeadElected := s.r.leadElectedTime()
		prevLeadLost := curLeadElected.Add(-2 * time.Duration(s.Cfg.ElectionTicks) * time.Duration(s.Cfg.TickMs) * time.Millisecond)
		if start.After(prevLeadLost) && start.Before(curLeadElected) {
			return ErrTimeoutDueToLeaderFail
		}

		lead := types.ID(atomic.LoadUint64(&s.r.lead))
		switch lead {
		case types.ID(raft.None):
			// TODO: return error to specify it happens because the cluster does not have leader now
		case s.ID():
			if !isConnectedToQuorumSince(s.r.transport, start, s.ID(), s.cluster.Members()) {
				return ErrTimeoutDueToConnectionLost
			}
		default:
			if !isConnectedSince(s.r.transport, start, lead) {
				return ErrTimeoutDueToConnectionLost
			}
		}

		return ErrTimeout
	default:
		return err
	}
}
// Creates an archive directory with the first version of start before archiveTime,
// or returns an error if start didn't exist before archiveTime
func (dir *Directory) mkDirectoryArchive(name string, archiveTime time.Time, start *Directory) (*Directory, error) {
	first := func() (*Directory, error) {
		return filesystem.getDirectory(start.getVid())
	}
	prev := func(curr *Directory) (*Directory, error) {
		return filesystem.getDirectory(curr.getLastVid())
	}
	for version, err := first(); err == nil && version != nil; version, err = prev(version) {
		var versionTime time.Time
		//versionTime := version.Attr().Mtime.Before(archiveTime)
		if UseMtime {
			versionTime = version.Attr().Mtime
		} else {
			versionTime = version.Vtime
		}
		if versionTime.Before(archiveTime) {
			version.Name = name
			version.archive = true
			version.childrenInMemory = false
			// Never saving these, so purposefully don't add them to
			// ChildVids and IsDir
			version.parent = dir
			dir.children[version.Name] = version
			return version, nil
		}
	}
	return nil, fuse.ENOENT
}