func (this *FD) _checkAndSubmitNumberZero_SansLock() {
	if this.nextAvailablePosition > 0 {
		return
	}

	this.nextAvailablePosition++
	// submit a empty patch to number zero

	var selfName = CONF_FLAG_PREFIX + NODE_SYNC_TIME_PREFIX + strconv.Itoa(NODE_NUMBER)
	var object = filetype.NewKvMap()
	object.TSet(0)
	object.CheckOut()
	object.Kvm[selfName] = &filetype.KvmapEntry{
		Key:       selfName,
		Val:       "",
		Timestamp: 0,
	}
	object.CheckIn()

	var err error
	var unrevocable_io_sleep_time_dur = time.Duration(TRIAL_INTERVAL_IN_UNREVOCABLE_IOERROR) * time.Millisecond
	for {
		err = this.io.Put(this.GetPatchName(0, -1), object,
			FileMeta(map[string]string{
				INTRA_PATCH_METAKEY_NEXT_PATCH: strconv.Itoa(1),
				METAKEY_TIMESTAMP:              "0",
			}))
		if err != nil {
			Secretary.Error("distributedvc::FD._checkAndSubmitNumberZero_SansLock", "Error trying to write an empty zero patch for "+this.ID()+
				": "+
				err.Error()+
				". Subsequent patches may lost. TRYING to resubmit...")
			time.Sleep(unrevocable_io_sleep_time_dur)
		} else {
			break
		}
	}

	this.contentLock.Lock()
	defer this.contentLock.Unlock()

	this.numberZero = object
	this.nextToBeMerge = 1
	this.latestReadableVersionTS = 0
	this.modified = false
}
// @ Must be Grasped Reader to use
func (this *FD) ReadInNumberZero() error {
	this.lock.Lock()
	defer this.lock.Unlock()

	this.contentLock.Lock()
	defer this.contentLock.Unlock()

	if this.numberZero != nil {
		return nil
	}

	var tMeta, tFile, tErr = this.io.Get(this.GetPatchName(0, -1))
	if tErr != nil {
		return tErr
	}
	if tFile == nil || tMeta == nil {
		return READ_ZERO_NONEXISTENCE
	}
	var tKvmap, ok = tFile.(*filetype.Kvmap)
	if !ok {
		Secretary.WarnD("File " + this.filename + "'s patch #0 has invalid filetype. Its content will get ignored.")
		this.numberZero = filetype.NewKvMap()
	} else {
		this.numberZero = tKvmap
	}
	this.numberZero.TSet(this.GetTSFromMeta(tMeta))
	if tNext, ok2 := tMeta[INTRA_PATCH_METAKEY_NEXT_PATCH]; !ok2 {
		Secretary.WarnD("File " + this.filename + "'s patch #0 has invalid next-patch. Its precedents will get ignored.")
		this.nextToBeMerge = 1
	} else {
		if nextNum, errx := strconv.Atoi(tNext); errx != nil {
			Secretary.WarnD("File " + this.filename + "'s patch #0 has invalid next-patch. Its precedents will get ignored.")
			this.nextToBeMerge = 1
		} else {
			this.nextToBeMerge = nextNum
		}
	}
	this.status = 1
	this.modified = false
	this.needsGossiped = false
	return nil
}
Exemple #3
0
func (this *Fs) BatchPutDir(filenameprefix string, frominode string, fromn int, ton int, content string) error {
	var kvmp = filetype.NewKvMap()
	var nowTime = GetTimestamp()
	kvmp.CheckOut()

	for i := fromn; i < ton; i++ {
		var filename = filenameprefix + strconv.Itoa(i)
		var nnodeName = GenFileName(frominode, filename)
		var newNnode = filetype.NewNnode(content)
		var initMeta = FileMeta(map[string]string{
			META_INODE_TYPE:   META_INODE_TYPE_FOLDER,
			META_PARENT_INODE: frominode,
		})
		if err := this.io.Put(nnodeName, newNnode, initMeta); err != nil {
			Secretary.Error("kernel/filesystem::Fs::BatchPutDir", "Error when putting "+filename+": "+err.Error())
			return err
		}
		kvmp.Kvm[filename] = &filetype.KvmapEntry{
			Key:       filename,
			Val:       "",
			Timestamp: nowTime,
		}
	}
	kvmp.CheckIn()
	kvmp.TSet(nowTime)

	{
		var parentFolderMapFD = dvc.GetFD(GenFileName(frominode, FOLDER_MAP), this.io)
		if parentFolderMapFD == nil {
			Secretary.Error("kernel.filesystem::BatchPutDir", "Fail to create foldermap")
			return exception.EX_IO_ERROR
		}
		if err := parentFolderMapFD.Submit(kvmp); err != nil {
			Secretary.Error("kernel.filesystem::BatchPutDir", "Fail to submit patch to foldermap")
			parentFolderMapFD.Release()
			return err
		}
		parentFolderMapFD.Release()
	}

	return nil
}
// Read and combine all the version from other nodes, providing the combined version.
// @ Get Reader Grasped
func (this *FD) __deprecated__Sync() error {
	var nowTime = time.Now().Unix()
	if this.lastSyncTime+SINGLE_FILE_SYNC_INTERVAL_MIN > nowTime {
		// interval is too small, abort the sync.
		return nil
	}
	// Submit #0 patch if needed
	this._LoadPointerMap_SyncUseOnly()

	// read patch 0 from container. If just submit, the function will exit immediately
	this.ReadInNumberZero()

	this.contentLock.Lock()
	defer this.contentLock.Unlock()

	if this.lastSyncTime+SINGLE_FILE_SYNC_INTERVAL_MIN > nowTime {
		// interval is too small, abort the sync.
		return nil
	}

	if this.numberZero == nil {
		Insider.Log("distributedvc::FD.Sync()", "Looks like a logical isle: this.numberZero==nil")
		Secretary.Error("distributedvc::FD.Sync()", "Looks like a logical isle: this.numberZero==nil")
		return ex.LOGICAL_ERROR
	}

	// phase1: glean information from different nodes
	// Attentez: the go routines will read numberZero.Kvm but will not write it. So not lock is required.

	this.numberZero.CheckOut()

	var updateChannel = make(chan int, NODE_NUMS_IN_ALL)
	go (func() {
		var wg = sync.WaitGroup{}
		var gleanInfo = func(nodeNumber int) bool {
			defer wg.Done()

			if nodeNumber == NODE_NUMBER {
				return false
			}
			var keyStoreName = CONF_FLAG_PREFIX + NODE_SYNC_TIME_PREFIX + strconv.Itoa(nodeNumber)
			var lastTime ClxTimestamp
			if elem, ok := this.numberZero.Kvm[keyStoreName]; ok {
				lastTime = elem.Timestamp
			} else {
				lastTime = 0
			}

			if lastTime > 0 {
				var meta, err = this.io.Getinfo(this.GetPatchName(0, nodeNumber))
				if meta == nil || err != nil {
					if err != nil {
						Secretary.Warn("distributedvc::FD.Sync()", "Fail to get info from "+this.GetPatchName(0, nodeNumber)+": "+err.Error())
					}
					return false
				}
				var result, ok = meta[METAKEY_TIMESTAMP]
				if !ok {
					return false
				}
				var existRecentTS = String2ClxTimestamp(result)
				if existRecentTS > lastTime {
					updateChannel <- nodeNumber
					return true
				}
				return false
			}

			updateChannel <- nodeNumber
			return true
		}
		wg.Add(NODE_NUMS_IN_ALL)
		for i := 0; i < NODE_NUMS_IN_ALL; i++ {
			go gleanInfo(i)
		}
		wg.Wait()
		close(updateChannel)
	})()

	// meanwhile: fetch corresponding patch as need
	var thePatch = filetype.NewKvMap()
	var changed = false
	for i := range updateChannel {
		var file, _, err = readInKvMapfile_NoWarning(this.io, this.GetPatchName(0, i))
		if err != nil {
			Secretary.Warn("distributedvc::FD.Sync()", "Fail to read supposed-to-be file "+this.GetPatchName(0, i))
			continue
		}
		if file == nil {
			continue
		}
		thePatch.MergeWith(file)
		changed = true
	}
	// At this time, the channel must be closed and thus, all the reading routines of
	// this.numberZero has terminated safely, on which any write is thread-safe.
	if changed {
		// merging to update modification timestamp
		this.numberZero.MergeWith(filetype.FastMake(CONF_FLAG_PREFIX + NODE_SYNC_TIME_PREFIX + strconv.Itoa(NODE_NUMBER)))
		this.numberZero.MergeWith(thePatch)
		this.modified = true
		this.needsGossiped = true
	}
	this.lastSyncTime = time.Now().Unix()

	return nil
}