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 }
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 }