[VOL-4303] OpenOnuAdapter Onu Upgrade mismatch in adapter file download state - no ONU upgrade start

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I1dc4a77b39e38640d7a9c6dbdf6c0027754ffae7
diff --git a/VERSION b/VERSION
index 46b58a7..1cf8619 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.1-dev223
+1.4.1-dev224
diff --git a/internal/pkg/onuadaptercore/file_download_manager.go b/internal/pkg/onuadaptercore/file_download_manager.go
index 3767df2..00440c1 100644
--- a/internal/pkg/onuadaptercore/file_download_manager.go
+++ b/internal/pkg/onuadaptercore/file_download_manager.go
@@ -165,6 +165,12 @@
 
 //RequestDownloadReady receives a channel that has to be used to inform the requester in case the concerned file is downloaded
 func (dm *fileDownloadManager) RequestDownloadReady(ctx context.Context, aFileName string, aWaitChannel chan<- bool) {
+	//mutexDownloadImageDsc must already be locked here to avoid an update of the dnldImgReadyWaiting map
+	//  just after returning false on imageLocallyDownloaded() (not found) and immediate handling of the
+	//  download success (within updateFileState())
+	//  so updateFileState() can't interfere here just after imageLocallyDownloaded() before setting the requester map
+	dm.mutexDownloadImageDsc.Lock()
+	defer dm.mutexDownloadImageDsc.Unlock()
 	if dm.imageLocallyDownloaded(ctx, aFileName) {
 		//image found (by name) and fully downloaded
 		logger.Debugw(ctx, "file ready - immediate response", log.Fields{"image-name": aFileName})
@@ -173,8 +179,6 @@
 	}
 	//when we are here the image was not yet found or not fully downloaded -
 	//  add the device specific channel to the list of waiting requesters
-	dm.mutexDownloadImageDsc.Lock()
-	defer dm.mutexDownloadImageDsc.Unlock()
 	if loRequesterChannelMap, ok := dm.dnldImgReadyWaiting[aFileName]; ok {
 		//entry for the file name already exists
 		if _, exists := loRequesterChannelMap[aWaitChannel]; !exists {
@@ -216,11 +220,9 @@
 // FileDownloadManager private (unexported) methods -- start
 
 //imageLocallyDownloaded returns true if the requested image already exists within the adapter
+//  requires mutexDownloadImageDsc to be locked (at least RLocked)
 func (dm *fileDownloadManager) imageLocallyDownloaded(ctx context.Context, aImageName string) bool {
 	logger.Debugw(ctx, "checking if image is fully downloaded to adapter", log.Fields{"image-name": aImageName})
-	dm.mutexDownloadImageDsc.RLock()
-	defer dm.mutexDownloadImageDsc.RUnlock()
-
 	for _, dnldImgDsc := range dm.downloadImageDscSlice {
 		if dnldImgDsc.downloadImageName == aImageName {
 			//image found (by name)
@@ -237,6 +239,33 @@
 	return false
 }
 
+//updateFileState sets the new active (downloaded) file state and informs possibly waiting requesters on this change
+func (dm *fileDownloadManager) updateFileState(ctx context.Context, aImageName string, aFileSize int64) {
+	dm.mutexDownloadImageDsc.Lock()
+	defer dm.mutexDownloadImageDsc.Unlock()
+	for imgKey, dnldImgDsc := range dm.downloadImageDscSlice {
+		if dnldImgDsc.downloadImageName == aImageName {
+			//image found (by name) - need to write changes on the original map
+			dm.downloadImageDscSlice[imgKey].downloadImageState = cFileStateDlSucceeded
+			dm.downloadImageDscSlice[imgKey].downloadImageLen = aFileSize
+			logger.Debugw(ctx, "imageState download succeeded", log.Fields{
+				"image-name": aImageName, "image-size": aFileSize})
+			//in case upgrade process(es) was/were waiting for the file, inform them
+			for imageName, channelMap := range dm.dnldImgReadyWaiting {
+				if imageName == aImageName {
+					for channel := range channelMap {
+						// use all found channels to inform possible requesters about the existence of the file
+						channel <- true
+						delete(dm.dnldImgReadyWaiting[imageName], channel) //requester served
+					}
+					return //can leave directly
+				}
+			}
+			return //can leave directly
+		}
+	}
+}
+
 //downloadFile downloads the specified file from the given http location
 func (dm *fileDownloadManager) downloadFile(ctx context.Context, aURLCommand string, aFilePath string, aFileName string) error {
 	// Get the data
@@ -329,31 +358,12 @@
 		fileStats, statsErr := file.Stat()
 		if err != nil {
 			logger.Errorw(ctx, "created file can't be accessed", log.Fields{"file": aLocalPathName, "stat-error": statsErr})
+			return
 		}
 		fileSize := fileStats.Size()
 		logger.Infow(ctx, "written file size is", log.Fields{"file": aLocalPathName, "length": fileSize})
 
-		dm.mutexDownloadImageDsc.Lock()
-		defer dm.mutexDownloadImageDsc.Unlock()
-		for imgKey, dnldImgDsc := range dm.downloadImageDscSlice {
-			if dnldImgDsc.downloadImageName == aFileName {
-				//image found (by name) - need to write changes on the original map
-				dm.downloadImageDscSlice[imgKey].downloadImageState = cFileStateDlSucceeded
-				dm.downloadImageDscSlice[imgKey].downloadImageLen = fileSize
-				//in case upgrade process(es) was/were waiting for the file, inform them
-				for imageName, channelMap := range dm.dnldImgReadyWaiting {
-					if imageName == aFileName {
-						for channel := range channelMap {
-							// use all found channels to inform possible requesters about the existence of the file
-							channel <- true
-							delete(dm.dnldImgReadyWaiting[imageName], channel) //requester served
-						}
-						return //can leave directly
-					}
-				}
-				return //can leave directly
-			}
-		}
+		dm.updateFileState(ctx, aFileName, fileSize)
 		//TODO:!!! further extension could be provided here, e.g. already computing and possibly comparing the CRC, vendor check
 	}()
 	return nil