github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/transitions/api_internal.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package transitions
     5  
     6  import (
     7  	"container/list"
     8  	"fmt"
     9  	"sync"
    10  
    11  	"github.com/swiftstack/ProxyFS/conf"
    12  	"github.com/swiftstack/ProxyFS/logger"
    13  )
    14  
    15  type loggerCallbacksInterfaceStruct struct {
    16  }
    17  
    18  var loggerCallbacksInterface loggerCallbacksInterfaceStruct
    19  
    20  type registrationItemStruct struct {
    21  	packageName string
    22  	callbacks   Callbacks
    23  }
    24  
    25  type volumeStruct struct {
    26  	name        string
    27  	served      bool
    28  	volumeGroup *volumeGroupStruct
    29  }
    30  
    31  type volumeGroupStruct struct {
    32  	name          string
    33  	served        bool
    34  	activePeer    string
    35  	virtualIPAddr string
    36  	volumeList    map[string]*volumeStruct // Key: volumeStruct.name
    37  }
    38  
    39  type confMapDeltaStruct struct {
    40  	volumeGroupList       map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    41  	servedVolumeGroupList map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    42  	remoteVolumeGroupList map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    43  
    44  	createdVolumeGroupList   map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    45  	movedVolumeGroupList     map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    46  	destroyedVolumeGroupList map[string]*volumeGroupStruct // Key: volumeGroupStruct.name
    47  
    48  	volumeList       map[string]*volumeStruct // Key: volumeStruct.name
    49  	servedVolumeList map[string]*volumeStruct // Key: volumeStruct.name
    50  	remoteVolumeList map[string]*volumeStruct // Key: volumeStruct.name
    51  
    52  	createdVolumeList   map[string]*volumeStruct // Key: volumeStruct.name
    53  	movedVolumeList     map[string]*volumeStruct // Key: volumeStruct.name
    54  	destroyedVolumeList map[string]*volumeStruct // Key: volumeStruct.name
    55  
    56  	toStopServingVolumeList  map[string]*volumeStruct // Key: volumeStruct.name
    57  	toStartServingVolumeList map[string]*volumeStruct // Key: volumeStruct.name
    58  }
    59  
    60  type globalsStruct struct {
    61  	sync.Mutex          //                                    Used only for protecting insertions into registration{List|Set} during init() phase
    62  	registrationList    *list.List
    63  	registrationSet     map[string]*registrationItemStruct // Key: registrationItemStruct.packageName
    64  	currentConfMapDelta *confMapDeltaStruct
    65  }
    66  
    67  var globals globalsStruct
    68  
    69  func init() {
    70  	globals.Lock()
    71  	globals.registrationList = list.New()
    72  	globals.registrationSet = make(map[string]*registrationItemStruct)
    73  	globals.Unlock()
    74  
    75  	Register("logger", &loggerCallbacksInterface)
    76  }
    77  
    78  func register(packageName string, callbacks Callbacks) {
    79  	var (
    80  		alreadyRegisted  bool
    81  		registrationItem *registrationItemStruct
    82  	)
    83  
    84  	globals.Lock()
    85  	_, alreadyRegisted = globals.registrationSet[packageName]
    86  	if alreadyRegisted {
    87  		logger.Fatalf("transitions.Register(%s,) called twice", packageName)
    88  	}
    89  	registrationItem = &registrationItemStruct{packageName, callbacks}
    90  	_ = globals.registrationList.PushBack(registrationItem)
    91  	globals.registrationSet[packageName] = registrationItem
    92  	globals.Unlock()
    93  }
    94  
    95  func up(confMap conf.ConfMap) (err error) {
    96  	var (
    97  		newConfMapDelta                        *confMapDeltaStruct
    98  		registrationItem                       *registrationItemStruct
    99  		registrationListElement                *list.Element
   100  		registrationListPackageNameStringSlice []string
   101  		volume                                 *volumeStruct
   102  		volumeGroup                            *volumeGroupStruct
   103  		volumeGroupName                        string
   104  		volumeName                             string
   105  	)
   106  
   107  	defer func() {
   108  		if nil == err {
   109  			logger.Infof("transitions.Up() returning successfully")
   110  		} else {
   111  			// On the relatively good likelihood that at least logger.Up() worked...
   112  			logger.Errorf("transitions.Up() returning with failure: %v", err)
   113  		}
   114  	}()
   115  
   116  	globals.currentConfMapDelta = &confMapDeltaStruct{
   117  		volumeGroupList:       make(map[string]*volumeGroupStruct),
   118  		servedVolumeGroupList: make(map[string]*volumeGroupStruct),
   119  		remoteVolumeGroupList: make(map[string]*volumeGroupStruct),
   120  
   121  		createdVolumeGroupList:   make(map[string]*volumeGroupStruct),
   122  		movedVolumeGroupList:     make(map[string]*volumeGroupStruct),
   123  		destroyedVolumeGroupList: make(map[string]*volumeGroupStruct),
   124  
   125  		volumeList:       make(map[string]*volumeStruct),
   126  		servedVolumeList: make(map[string]*volumeStruct),
   127  		remoteVolumeList: make(map[string]*volumeStruct),
   128  
   129  		createdVolumeList:   make(map[string]*volumeStruct),
   130  		movedVolumeList:     make(map[string]*volumeStruct),
   131  		destroyedVolumeList: make(map[string]*volumeStruct),
   132  
   133  		toStopServingVolumeList:  make(map[string]*volumeStruct),
   134  		toStartServingVolumeList: make(map[string]*volumeStruct),
   135  	}
   136  
   137  	newConfMapDelta, err = computeConfMapDelta(confMap)
   138  	if nil != err {
   139  		return
   140  	}
   141  
   142  	if 0 != len(newConfMapDelta.movedVolumeGroupList) {
   143  		err = fmt.Errorf("transitions.Up() did not expect movedVolumeGroupList to be non-empty")
   144  		return
   145  	}
   146  	if 0 != len(newConfMapDelta.destroyedVolumeGroupList) {
   147  		err = fmt.Errorf("transitions.Up() did not expect destroyedVolumeGroupList to be non-empty")
   148  		return
   149  	}
   150  	if 0 != len(newConfMapDelta.movedVolumeList) {
   151  		err = fmt.Errorf("transitions.Up() did not expect movedVolumeList to be non-empty")
   152  		return
   153  	}
   154  	if 0 != len(newConfMapDelta.destroyedVolumeList) {
   155  		err = fmt.Errorf("transitions.Up() did not expect destroyedVolumeList to be non-empty")
   156  		return
   157  	}
   158  
   159  	globals.currentConfMapDelta = newConfMapDelta
   160  
   161  	// Issue Callbacks.Up() calls from Front() to Back() of globals.registrationList
   162  
   163  	registrationListElement = globals.registrationList.Front()
   164  
   165  	for nil != registrationListElement {
   166  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   167  		logger.Tracef("transitions.Up() calling %s.Up()", registrationItem.packageName)
   168  		err = registrationItem.callbacks.Up(confMap)
   169  		if nil != err {
   170  			logger.Errorf("transitions.Up() call to %s.Up() failed: %v", registrationItem.packageName, err)
   171  			err = fmt.Errorf("%s.Up() failed: %v", registrationItem.packageName, err)
   172  			return
   173  		}
   174  		registrationListElement = registrationListElement.Next()
   175  	}
   176  
   177  	// Log transitions registrationList from Front() to Back()
   178  
   179  	registrationListPackageNameStringSlice = make([]string, 0, globals.registrationList.Len())
   180  
   181  	registrationListElement = globals.registrationList.Front()
   182  
   183  	for nil != registrationListElement {
   184  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   185  		registrationListPackageNameStringSlice = append(registrationListPackageNameStringSlice, registrationItem.packageName)
   186  		registrationListElement = registrationListElement.Next()
   187  	}
   188  
   189  	logger.Infof("Transitions Package Registration List: %v", registrationListPackageNameStringSlice)
   190  
   191  	// Issue Callbacks.VolumeGroupCreated() calls from Front() to Back() of globals.registrationList
   192  
   193  	registrationListElement = globals.registrationList.Front()
   194  
   195  	for nil != registrationListElement {
   196  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   197  		for volumeGroupName, volumeGroup = range globals.currentConfMapDelta.createdVolumeGroupList {
   198  			logger.Tracef("transitions.Up() calling %s.VolumeGroupCreated(,%s,%s,%s)", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   199  			err = registrationItem.callbacks.VolumeGroupCreated(confMap, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   200  			if nil != err {
   201  				logger.Errorf("transitions.Up() call to %s.VolumeGroupCreated(,%s,%s,%s) failed: %v", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr, err)
   202  				err = fmt.Errorf("%s.VolumeGroupCreated(,%s,,) failed: %v", registrationItem.packageName, volumeGroupName, err)
   203  				return
   204  			}
   205  		}
   206  		registrationListElement = registrationListElement.Next()
   207  	}
   208  
   209  	// Issue Callbacks.VolumeCreated() calls from Front() to Back() of globals.registrationList
   210  
   211  	registrationListElement = globals.registrationList.Front()
   212  
   213  	for nil != registrationListElement {
   214  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   215  		for volumeName, volume = range globals.currentConfMapDelta.createdVolumeList {
   216  			logger.Tracef("transitions.Up() calling %s.VolumeCreated(,%s,%s)", registrationItem.packageName, volumeName, volume.volumeGroup.name)
   217  			err = registrationItem.callbacks.VolumeCreated(confMap, volumeName, volume.volumeGroup.name)
   218  			if nil != err {
   219  				logger.Errorf("transitions.Up() call to %s.VolumeCreated(,%s,%s) failed: %v", registrationItem.packageName, volumeName, volume.volumeGroup.name, err)
   220  				err = fmt.Errorf("%s.VolumeCreated(,%s,) failed: %v", registrationItem.packageName, volumeName, err)
   221  				return
   222  			}
   223  		}
   224  		registrationListElement = registrationListElement.Next()
   225  	}
   226  
   227  	// Issue Callbacks.ServeVolume() calls from Front() to Back() of globals.registrationList
   228  
   229  	registrationListElement = globals.registrationList.Front()
   230  
   231  	for nil != registrationListElement {
   232  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   233  		for volumeName, volume = range globals.currentConfMapDelta.servedVolumeList {
   234  			logger.Tracef("transitions.Up() calling %s.ServeVolume(,%s)", registrationItem.packageName, volumeName)
   235  			err = registrationItem.callbacks.ServeVolume(confMap, volumeName)
   236  			if nil != err {
   237  				logger.Errorf("transitions.Up() call to %s.ServeVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   238  				err = fmt.Errorf("%s.ServeVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   239  				return
   240  			}
   241  		}
   242  		registrationListElement = registrationListElement.Next()
   243  	}
   244  
   245  	// Issue Callbacks.SignaledFinish() calls from Front() to Back() of globals.registrationList
   246  
   247  	registrationListElement = globals.registrationList.Front()
   248  
   249  	for nil != registrationListElement {
   250  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   251  		logger.Tracef("transitions.SignaledFinish() calling %s.SignaledFinish()", registrationItem.packageName)
   252  		err = registrationItem.callbacks.SignaledFinish(confMap)
   253  		if nil != err {
   254  			logger.Errorf("transitions.SignaledFinish() call to %s.SignaledFinish() failed: %v", registrationItem.packageName, err)
   255  			err = fmt.Errorf("%s.SignaledFinish() failed: %v", registrationItem.packageName, err)
   256  			return
   257  		}
   258  		registrationListElement = registrationListElement.Next()
   259  	}
   260  
   261  	return
   262  }
   263  
   264  func signaled(confMap conf.ConfMap) (err error) {
   265  	var (
   266  		newConfMapDelta         *confMapDeltaStruct
   267  		registrationItem        *registrationItemStruct
   268  		registrationListElement *list.Element
   269  		volume                  *volumeStruct
   270  		volumeGroup             *volumeGroupStruct
   271  		volumeGroupName         string
   272  		volumeName              string
   273  	)
   274  
   275  	logger.Infof("transitions.Signaled() called")
   276  	defer func() {
   277  		if nil == err {
   278  			logger.Infof("transitions.Signaled() returning successfully")
   279  		} else {
   280  			logger.Errorf("transitions.Signaled() returning with failure: %v", err)
   281  		}
   282  	}()
   283  
   284  	newConfMapDelta, err = computeConfMapDelta(confMap)
   285  	if nil != err {
   286  		return
   287  	}
   288  
   289  	globals.currentConfMapDelta = newConfMapDelta
   290  
   291  	// Issue Callbacks.VolumeToBeUnserved() calls from Back() to Front() of globals.registrationList
   292  
   293  	registrationListElement = globals.registrationList.Back()
   294  
   295  	for nil != registrationListElement {
   296  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   297  		for volumeName = range globals.currentConfMapDelta.toStopServingVolumeList {
   298  			logger.Tracef("transitions.Signaled() calling %s.VolumeToBeUnserved(,%s)", registrationItem.packageName, volumeName)
   299  			err = registrationItem.callbacks.VolumeToBeUnserved(confMap, volumeName)
   300  			if nil != err {
   301  				logger.Errorf("transitions.Signaled() call to %s.VolumeToBeUnserved(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   302  				err = fmt.Errorf("%s.VolumeToBeUnserved(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   303  				return
   304  			}
   305  		}
   306  		registrationListElement = registrationListElement.Prev()
   307  	}
   308  
   309  	// Issue Callbacks.SignaledStart() calls from Back() to Front() of globals.registrationList
   310  
   311  	registrationListElement = globals.registrationList.Back()
   312  
   313  	for nil != registrationListElement {
   314  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   315  		logger.Tracef("transitions.Signaled() calling %s.SignaledStart()", registrationItem.packageName)
   316  		err = registrationItem.callbacks.SignaledStart(confMap)
   317  		if nil != err {
   318  			logger.Errorf("transitions.Signaled() call to %s.SignaledStart() failed: %v", registrationItem.packageName, err)
   319  			err = fmt.Errorf("%s.SignaledStart() failed: %v", registrationItem.packageName, err)
   320  			return
   321  		}
   322  		registrationListElement = registrationListElement.Prev()
   323  	}
   324  
   325  	// Issue Callbacks.UnserveVolume() calls from Back() to Front() of globals.registrationList
   326  
   327  	registrationListElement = globals.registrationList.Back()
   328  
   329  	for nil != registrationListElement {
   330  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   331  		for volumeName = range globals.currentConfMapDelta.toStopServingVolumeList {
   332  			logger.Tracef("transitions.Signaled() calling %s.UnserveVolume(,%s)", registrationItem.packageName, volumeName)
   333  			err = registrationItem.callbacks.UnserveVolume(confMap, volumeName)
   334  			if nil != err {
   335  				logger.Errorf("transitions.Signaled() call to %s.UnserveVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   336  				err = fmt.Errorf("%s.UnserveVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   337  				return
   338  			}
   339  		}
   340  		registrationListElement = registrationListElement.Prev()
   341  	}
   342  
   343  	// Issue Callbacks.VolumeGroupCreated() calls from Front() to Back() of globals.registrationList
   344  
   345  	registrationListElement = globals.registrationList.Front()
   346  
   347  	for nil != registrationListElement {
   348  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   349  		for volumeGroupName, volumeGroup = range globals.currentConfMapDelta.createdVolumeGroupList {
   350  			logger.Tracef("transitions.Signaled() calling %s.VolumeGroupCreated(,%s,%s,%s)", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   351  			err = registrationItem.callbacks.VolumeGroupCreated(confMap, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   352  			if nil != err {
   353  				logger.Errorf("transitions.Signaled() call to %s.VolumeGroupCreated(,%s,%s,%s) failed: %v", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr, err)
   354  				err = fmt.Errorf("%s.VolumeGroupCreated(,%s,,) failed: %v", registrationItem.packageName, volumeName, err)
   355  				return
   356  			}
   357  		}
   358  		registrationListElement = registrationListElement.Next()
   359  	}
   360  
   361  	// Issue Callbacks.VolumeCreated() calls from Front() to Back() of globals.registrationList
   362  
   363  	registrationListElement = globals.registrationList.Front()
   364  
   365  	for nil != registrationListElement {
   366  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   367  		for volumeName, volume = range globals.currentConfMapDelta.createdVolumeList {
   368  			logger.Tracef("transitions.Signaled() calling %s.VolumeCreated(,%s,%s)", registrationItem.packageName, volumeName, volume.volumeGroup.name)
   369  			err = registrationItem.callbacks.VolumeCreated(confMap, volumeName, volume.volumeGroup.name)
   370  			if nil != err {
   371  				logger.Errorf("transitions.Signaled() call to %s.VolumeCreated(,%s,%s) failed: %v", registrationItem.packageName, volumeName, volume.volumeGroup.name, err)
   372  				err = fmt.Errorf("%s.VolumeCreated(,%s,) failed: %v", registrationItem.packageName, volumeName, err)
   373  				return
   374  			}
   375  		}
   376  		registrationListElement = registrationListElement.Next()
   377  	}
   378  
   379  	// Issue Callbacks.VolumeGroupMoved() calls from Front() to Back() of globals.registrationList
   380  
   381  	registrationListElement = globals.registrationList.Front()
   382  
   383  	for nil != registrationListElement {
   384  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   385  		for volumeGroupName, volumeGroup = range globals.currentConfMapDelta.movedVolumeGroupList {
   386  			logger.Tracef("transitions.Signaled() calling %s.VolumeGroupMoved(,%s,%s,%s)", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   387  			err = registrationItem.callbacks.VolumeGroupMoved(confMap, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr)
   388  			if nil != err {
   389  				logger.Errorf("transitions.Signaled() call to %s.VolumeGroupMoved(,%s,%s,%s) failed: %v", registrationItem.packageName, volumeGroupName, volumeGroup.activePeer, volumeGroup.virtualIPAddr, err)
   390  				err = fmt.Errorf("%s.VolumeGroupMoved(,%s,,) failed: %v", registrationItem.packageName, volumeName, err)
   391  				return
   392  			}
   393  		}
   394  		registrationListElement = registrationListElement.Next()
   395  	}
   396  
   397  	// Issue Callbacks.VolumeMoved() calls from Front() to Back() of globals.registrationList
   398  
   399  	registrationListElement = globals.registrationList.Front()
   400  
   401  	for nil != registrationListElement {
   402  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   403  		for volumeName, volume = range globals.currentConfMapDelta.movedVolumeList {
   404  			logger.Tracef("transitions.Signaled() calling %s.VolumeMoved(,%s,%s)", registrationItem.packageName, volumeName, volume.volumeGroup.name)
   405  			err = registrationItem.callbacks.VolumeMoved(confMap, volumeName, volume.volumeGroup.name)
   406  			if nil != err {
   407  				logger.Errorf("transitions.Signaled() call to %s.VolumeMoved(,%s,%s) failed: %v", registrationItem.packageName, volumeName, volume.volumeGroup.name, err)
   408  				err = fmt.Errorf("%s.VolumeMoved(,%s,) failed: %v", registrationItem.packageName, volumeName, err)
   409  				return
   410  			}
   411  		}
   412  		registrationListElement = registrationListElement.Next()
   413  	}
   414  
   415  	// Issue Callbacks.VolumeDestroyed() calls from Back() to Front() of globals.registrationList
   416  
   417  	registrationListElement = globals.registrationList.Back()
   418  
   419  	for nil != registrationListElement {
   420  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   421  		for volumeName, volume = range globals.currentConfMapDelta.destroyedVolumeList {
   422  			logger.Tracef("transitions.Signaled() calling %s.VolumeDestroyed(,%s)", registrationItem.packageName, volumeName)
   423  			err = registrationItem.callbacks.VolumeDestroyed(confMap, volumeName)
   424  			if nil != err {
   425  				logger.Errorf("transitions.Signaled() call to %s.VolumeDestroyed(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   426  				err = fmt.Errorf("%s.VolumeDestroyed(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   427  				return
   428  			}
   429  		}
   430  		registrationListElement = registrationListElement.Prev()
   431  	}
   432  
   433  	// Issue Callbacks.VolumeGroupDestroyed() calls from Back() to Front() of globals.registrationList
   434  
   435  	registrationListElement = globals.registrationList.Back()
   436  
   437  	for nil != registrationListElement {
   438  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   439  		for volumeGroupName = range globals.currentConfMapDelta.destroyedVolumeGroupList {
   440  			logger.Tracef("transitions.Signaled() calling %s.VolumeGroupDestroyed(,%s)", registrationItem.packageName, volumeGroupName)
   441  			err = registrationItem.callbacks.VolumeGroupDestroyed(confMap, volumeGroupName)
   442  			if nil != err {
   443  				logger.Errorf("transitions.Signaled() call to %s.VolumeGroupDestroyed(,%s) failed: %v", registrationItem.packageName, volumeGroupName, err)
   444  				err = fmt.Errorf("%s.VolumeGroupDestroyed(,%s) failed: %v", registrationItem.packageName, volumeGroupName, err)
   445  				return
   446  			}
   447  		}
   448  		registrationListElement = registrationListElement.Prev()
   449  	}
   450  
   451  	// Issue Callbacks.ServeVolume() calls from Front() to Back() of globals.registrationList
   452  
   453  	registrationListElement = globals.registrationList.Front()
   454  
   455  	for nil != registrationListElement {
   456  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   457  		for volumeName, volume = range globals.currentConfMapDelta.toStartServingVolumeList {
   458  			if volume.served {
   459  				logger.Tracef("transitions.Signaled() calling %s.ServeVolume(,%s)", registrationItem.packageName, volumeGroupName)
   460  				err = registrationItem.callbacks.ServeVolume(confMap, volumeName)
   461  				if nil != err {
   462  					logger.Errorf("transitions.Signaled() call to %s.ServeVolume(,%s) failed: %v", registrationItem.packageName, volumeGroupName, err)
   463  					err = fmt.Errorf("%s.ServeVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   464  					return
   465  				}
   466  			}
   467  		}
   468  		registrationListElement = registrationListElement.Next()
   469  	}
   470  
   471  	// Issue Callbacks.SignaledFinish() calls from Front() to Back() of globals.registrationList
   472  
   473  	registrationListElement = globals.registrationList.Front()
   474  
   475  	for nil != registrationListElement {
   476  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   477  		logger.Tracef("transitions.Signaled() calling %s.SignaledFinish()", registrationItem.packageName)
   478  		err = registrationItem.callbacks.SignaledFinish(confMap)
   479  		if nil != err {
   480  			logger.Errorf("transitions.Signaled() call to %s.SignaledFinish() failed: %v", registrationItem.packageName, err)
   481  			err = fmt.Errorf("%s.SignaledFinish() failed: %v", registrationItem.packageName, err)
   482  			return
   483  		}
   484  		registrationListElement = registrationListElement.Next()
   485  	}
   486  
   487  	return
   488  }
   489  
   490  func down(confMap conf.ConfMap) (err error) {
   491  	var (
   492  		newConfMapDelta         *confMapDeltaStruct
   493  		registrationItem        *registrationItemStruct
   494  		registrationListElement *list.Element
   495  		volumeGroupName         string
   496  		volumeName              string
   497  	)
   498  
   499  	logger.Infof("transitions.Down() called")
   500  	defer func() {
   501  		if nil != err {
   502  			// On the relatively good likelihood that the failure occurred before calling logger.Down()...
   503  			logger.Errorf("transitions.Down() returning with failure: %v", err)
   504  		}
   505  	}()
   506  
   507  	newConfMapDelta, err = computeConfMapDelta(confMap)
   508  	if nil != err {
   509  		return
   510  	}
   511  
   512  	if 0 != len(newConfMapDelta.createdVolumeGroupList) {
   513  		err = fmt.Errorf("transitions.Down() did not expect createdVolumeGroupList to be non-empty")
   514  		return
   515  	}
   516  	if 0 != len(newConfMapDelta.movedVolumeGroupList) {
   517  		err = fmt.Errorf("transitions.Down() did not expect movedVolumeGroupList to be non-empty")
   518  		return
   519  	}
   520  	if 0 != len(newConfMapDelta.destroyedVolumeGroupList) {
   521  		err = fmt.Errorf("transitions.Down() did not expect destroyedVolumeGroupList to be non-empty")
   522  		return
   523  	}
   524  	if 0 != len(newConfMapDelta.createdVolumeList) {
   525  		err = fmt.Errorf("transitions.Down() did not expect createdVolumeList to be non-empty")
   526  		return
   527  	}
   528  	if 0 != len(newConfMapDelta.movedVolumeList) {
   529  		err = fmt.Errorf("transitions.Down() did not expect movedVolumeList to be non-empty")
   530  		return
   531  	}
   532  	if 0 != len(newConfMapDelta.destroyedVolumeList) {
   533  		err = fmt.Errorf("transitions.Down() did not expect destroyedVolumeList to be non-empty")
   534  		return
   535  	}
   536  
   537  	globals.currentConfMapDelta = newConfMapDelta
   538  
   539  	// Issue Callbacks.VolumeToBeUnserved() calls from Back() to Front() of globals.registrationList
   540  
   541  	registrationListElement = globals.registrationList.Back()
   542  
   543  	for nil != registrationListElement {
   544  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   545  		for volumeName = range globals.currentConfMapDelta.servedVolumeList {
   546  			logger.Tracef("transitions.Signaled() calling %s.VolumeToBeUnserved(,%s)", registrationItem.packageName, volumeName)
   547  			err = registrationItem.callbacks.VolumeToBeUnserved(confMap, volumeName)
   548  			if nil != err {
   549  				logger.Errorf("transitions.Signaled() call to %s.VolumeToBeUnserved(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   550  				err = fmt.Errorf("%s.VolumeToBeUnserved(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   551  				return
   552  			}
   553  		}
   554  		registrationListElement = registrationListElement.Prev()
   555  	}
   556  
   557  	// Issue Callbacks.SignaledStart() calls from Back() to Front() of globals.registrationList
   558  
   559  	registrationListElement = globals.registrationList.Back()
   560  
   561  	for nil != registrationListElement {
   562  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   563  		logger.Tracef("transitions.Down() calling %s.SignaledStart()", registrationItem.packageName)
   564  		err = registrationItem.callbacks.SignaledStart(confMap)
   565  		if nil != err {
   566  			logger.Errorf("transitions.Down() call to %s.SignaledStart() failed: %v", registrationItem.packageName, err)
   567  			err = fmt.Errorf("%s.SignaledStart() failed: %v", registrationItem.packageName, err)
   568  			return
   569  		}
   570  		registrationListElement = registrationListElement.Prev()
   571  	}
   572  
   573  	// Issue Callbacks.UnserveVolume() calls from Back() to Front() of globals.registrationList
   574  
   575  	registrationListElement = globals.registrationList.Back()
   576  
   577  	for nil != registrationListElement {
   578  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   579  		for volumeName = range globals.currentConfMapDelta.servedVolumeList {
   580  			logger.Tracef("transitions.Down() calling %s.UnserveVolume(,%s)", registrationItem.packageName, volumeName)
   581  			err = registrationItem.callbacks.UnserveVolume(confMap, volumeName)
   582  			if nil != err {
   583  				logger.Errorf("transitions.Down() call to %s.UnserveVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   584  				err = fmt.Errorf("%s.UnserveVolume(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   585  				return
   586  			}
   587  		}
   588  		registrationListElement = registrationListElement.Prev()
   589  	}
   590  
   591  	// Issue Callbacks.VolumeDestroyed() calls from Back() to Front() of globals.registrationList
   592  
   593  	registrationListElement = globals.registrationList.Back()
   594  
   595  	for nil != registrationListElement {
   596  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   597  		for volumeName = range globals.currentConfMapDelta.volumeList {
   598  			logger.Tracef("transitions.Down() calling %s.VolumeDestroyed(,%s)", registrationItem.packageName, volumeName)
   599  			err = registrationItem.callbacks.VolumeDestroyed(confMap, volumeName)
   600  			if nil != err {
   601  				logger.Errorf("transitions.Down() call to %s.VolumeDestroyed(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   602  				err = fmt.Errorf("%s.VolumeDestroyed(,%s) failed: %v", registrationItem.packageName, volumeName, err)
   603  				return
   604  			}
   605  		}
   606  		registrationListElement = registrationListElement.Prev()
   607  	}
   608  
   609  	// Issue Callbacks.VolumeGroupDestroyed() calls from Back() to Front() of globals.registrationList
   610  
   611  	registrationListElement = globals.registrationList.Back()
   612  
   613  	for nil != registrationListElement {
   614  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   615  		for volumeGroupName = range globals.currentConfMapDelta.volumeGroupList {
   616  			logger.Tracef("transitions.Down() calling %s.VolumeGroupDestroyed(,%s)", registrationItem.packageName, volumeGroupName)
   617  			err = registrationItem.callbacks.VolumeGroupDestroyed(confMap, volumeGroupName)
   618  			if nil != err {
   619  				logger.Errorf("transitions.Down() call to %s.VolumeGroupDestroyed(,%s) failed: %v", registrationItem.packageName, volumeGroupName, err)
   620  				err = fmt.Errorf("%s.VolumeGroupDestroyed(,%s) failed: %v", registrationItem.packageName, volumeGroupName, err)
   621  				return
   622  			}
   623  		}
   624  		registrationListElement = registrationListElement.Prev()
   625  	}
   626  
   627  	// Issue Callbacks.Down() calls from Back() to Front() of globals.registrationList
   628  
   629  	registrationListElement = globals.registrationList.Back()
   630  
   631  	for nil != registrationListElement {
   632  		registrationItem = registrationListElement.Value.(*registrationItemStruct)
   633  		logger.Tracef("transitions.Down() calling %s.Down()", registrationItem.packageName)
   634  		err = registrationItem.callbacks.Down(confMap)
   635  		if nil != err {
   636  			logger.Errorf("transitions.Down() call to %s.Down() failed: %v", registrationItem.packageName, err)
   637  			err = fmt.Errorf("%s.Down() failed: %v", registrationItem.packageName, err)
   638  			return
   639  		}
   640  		registrationListElement = registrationListElement.Prev()
   641  	}
   642  
   643  	return
   644  }
   645  
   646  func computeConfMapDelta(confMap conf.ConfMap) (newConfMapDelta *confMapDeltaStruct, err error) {
   647  	var (
   648  		fsGlobalsVolumeGroupList []string
   649  		ok                       bool
   650  		volume                   *volumeStruct
   651  		volumeGroup              *volumeGroupStruct
   652  		volumeGroupName          string
   653  		volumeGroupVolumeList    []string
   654  		volumeGroupPreviously    *volumeGroupStruct
   655  		volumeName               string
   656  		volumePreviously         *volumeStruct
   657  		whoAmI                   string
   658  	)
   659  
   660  	// TODO: Remove call to upgradeConfMapIfNeeded() once backwards compatibility is no longer required
   661  
   662  	err = upgradeConfMapIfNeeded(confMap)
   663  	if nil != err {
   664  		return
   665  	}
   666  
   667  	// Initialize lists used in computation
   668  
   669  	newConfMapDelta = &confMapDeltaStruct{
   670  		volumeGroupList:       make(map[string]*volumeGroupStruct),
   671  		servedVolumeGroupList: make(map[string]*volumeGroupStruct),
   672  		remoteVolumeGroupList: make(map[string]*volumeGroupStruct),
   673  
   674  		createdVolumeGroupList:   make(map[string]*volumeGroupStruct),
   675  		movedVolumeGroupList:     make(map[string]*volumeGroupStruct),
   676  		destroyedVolumeGroupList: make(map[string]*volumeGroupStruct),
   677  
   678  		volumeList:       make(map[string]*volumeStruct),
   679  		servedVolumeList: make(map[string]*volumeStruct),
   680  		remoteVolumeList: make(map[string]*volumeStruct),
   681  
   682  		createdVolumeList:   make(map[string]*volumeStruct),
   683  		movedVolumeList:     make(map[string]*volumeStruct),
   684  		destroyedVolumeList: make(map[string]*volumeStruct),
   685  
   686  		toStopServingVolumeList:  make(map[string]*volumeStruct),
   687  		toStartServingVolumeList: make(map[string]*volumeStruct),
   688  	}
   689  
   690  	// Ingest confMap
   691  
   692  	whoAmI, err = confMap.FetchOptionValueString("Cluster", "WhoAmI")
   693  	if nil != err {
   694  		return
   695  	}
   696  
   697  	fsGlobalsVolumeGroupList, err = confMap.FetchOptionValueStringSlice("FSGlobals", "VolumeGroupList")
   698  	if nil != err {
   699  		return
   700  	}
   701  
   702  	for _, volumeGroupName = range fsGlobalsVolumeGroupList {
   703  		volumeGroup = &volumeGroupStruct{name: volumeGroupName, volumeList: make(map[string]*volumeStruct)}
   704  
   705  		newConfMapDelta.volumeGroupList[volumeGroupName] = volumeGroup
   706  
   707  		volumeGroup.activePeer, err = confMap.FetchOptionValueString("VolumeGroup:"+volumeGroupName, "PrimaryPeer")
   708  		if nil != err {
   709  			if nil == confMap.VerifyOptionValueIsEmpty("VolumeGroup:"+volumeGroupName, "PrimaryPeer") {
   710  				volumeGroup.activePeer = ""
   711  			} else {
   712  				return
   713  			}
   714  		}
   715  
   716  		volumeGroup.served = (whoAmI == volumeGroup.activePeer)
   717  
   718  		if volumeGroup.served {
   719  			newConfMapDelta.servedVolumeGroupList[volumeGroupName] = volumeGroup
   720  		} else {
   721  			newConfMapDelta.remoteVolumeGroupList[volumeGroupName] = volumeGroup
   722  		}
   723  
   724  		volumeGroup.virtualIPAddr, err = confMap.FetchOptionValueString("VolumeGroup:"+volumeGroupName, "VirtualIPAddr")
   725  		if nil != err {
   726  			if nil == confMap.VerifyOptionValueIsEmpty("VolumeGroup:"+volumeGroupName, "VirtualIPAddr") {
   727  				volumeGroup.virtualIPAddr = ""
   728  			} else {
   729  				return
   730  			}
   731  		}
   732  
   733  		volumeGroupVolumeList, err = confMap.FetchOptionValueStringSlice("VolumeGroup:"+volumeGroupName, "VolumeList")
   734  		if nil != err {
   735  			return
   736  		}
   737  
   738  		for _, volumeName = range volumeGroupVolumeList {
   739  			volume = &volumeStruct{name: volumeName, served: volumeGroup.served, volumeGroup: volumeGroup}
   740  
   741  			newConfMapDelta.volumeList[volumeName] = volume
   742  
   743  			if volume.served {
   744  				newConfMapDelta.servedVolumeList[volumeName] = volume
   745  			} else {
   746  				newConfMapDelta.remoteVolumeList[volumeName] = volume
   747  			}
   748  
   749  			volumeGroup.volumeList[volumeName] = volume
   750  		}
   751  	}
   752  
   753  	// Compute changes to VolumeGroupList
   754  
   755  	for volumeGroupName, volumeGroup = range newConfMapDelta.volumeGroupList {
   756  		volumeGroupPreviously, ok = globals.currentConfMapDelta.volumeGroupList[volumeGroupName]
   757  		if ok {
   758  			if volumeGroupPreviously.activePeer != volumeGroup.activePeer {
   759  				newConfMapDelta.movedVolumeGroupList[volumeGroupName] = volumeGroup
   760  			}
   761  		} else {
   762  			newConfMapDelta.createdVolumeGroupList[volumeGroupName] = volumeGroup
   763  		}
   764  	}
   765  
   766  	for volumeGroupName, volumeGroup = range globals.currentConfMapDelta.volumeGroupList {
   767  		_, ok = newConfMapDelta.volumeGroupList[volumeGroupName]
   768  		if !ok {
   769  			newConfMapDelta.destroyedVolumeGroupList[volumeGroupName] = volumeGroup
   770  		}
   771  	}
   772  
   773  	// Compute changes to VolumeList
   774  
   775  	for volumeName, volume = range newConfMapDelta.volumeList {
   776  		volumePreviously, ok = globals.currentConfMapDelta.volumeList[volumeName]
   777  		if ok {
   778  			if volumePreviously.volumeGroup.name != volume.volumeGroup.name {
   779  				newConfMapDelta.movedVolumeList[volumeName] = volume
   780  			}
   781  		} else {
   782  			newConfMapDelta.createdVolumeList[volumeName] = volume
   783  		}
   784  	}
   785  
   786  	for volumeName, volume = range globals.currentConfMapDelta.volumeList {
   787  		_, ok = newConfMapDelta.volumeList[volumeName]
   788  		if !ok {
   789  			newConfMapDelta.destroyedVolumeList[volumeName] = volume
   790  		}
   791  	}
   792  
   793  	// Compute to{Stop|Start}ServingVolumeList
   794  
   795  	for volumeName, volume = range newConfMapDelta.destroyedVolumeList {
   796  		_, ok = globals.currentConfMapDelta.servedVolumeList[volumeName]
   797  		if ok {
   798  			newConfMapDelta.toStopServingVolumeList[volumeName] = volume
   799  		}
   800  	}
   801  	for volumeName, volume = range newConfMapDelta.movedVolumeList {
   802  		_, ok = globals.currentConfMapDelta.servedVolumeList[volumeName]
   803  		if ok {
   804  			newConfMapDelta.toStopServingVolumeList[volumeName] = volume
   805  		}
   806  	}
   807  	for _, volumeGroup = range newConfMapDelta.movedVolumeGroupList {
   808  		for volumeName, volume = range volumeGroup.volumeList {
   809  			_, ok = globals.currentConfMapDelta.servedVolumeList[volumeName]
   810  			if ok {
   811  				newConfMapDelta.toStopServingVolumeList[volumeName] = volume
   812  			}
   813  		}
   814  	}
   815  
   816  	for _, volumeGroup = range newConfMapDelta.movedVolumeGroupList {
   817  		for volumeName, volume = range volumeGroup.volumeList {
   818  			_, ok = newConfMapDelta.servedVolumeList[volumeName]
   819  			if ok {
   820  				newConfMapDelta.toStartServingVolumeList[volumeName] = volume
   821  			}
   822  		}
   823  	}
   824  	for volumeName, volume = range newConfMapDelta.movedVolumeList {
   825  		_, ok = newConfMapDelta.servedVolumeList[volumeName]
   826  		if ok {
   827  			newConfMapDelta.toStartServingVolumeList[volumeName] = volume
   828  		}
   829  	}
   830  	for volumeName, volume = range newConfMapDelta.createdVolumeList {
   831  		_, ok = newConfMapDelta.servedVolumeList[volumeName]
   832  		if ok {
   833  			newConfMapDelta.toStartServingVolumeList[volumeName] = volume
   834  		}
   835  	}
   836  
   837  	// All done
   838  
   839  	err = nil
   840  	return
   841  }
   842  
   843  // upgradeConfMapIfNeeded should be removed once backwards compatibility is no longer required...
   844  //
   845  // In the meantime, the changes are:
   846  //
   847  //   MaxFlushSize                          moves from FlowControl: section to the Volume: section (for each Volume referencing it)
   848  //   MaxFlushTime                          moves from FlowControl: section to the Volume: section (for each Volume referencing it)
   849  //   FileDefragmentChunkSize  (if present) moves from FlowControl: section to the Volume: section (for each Volume referencing it)
   850  //   FileDefragmentChunkDelay (if present) moves from FlowControl: section to the Volume: section (for each Volume referencing it)
   851  //
   852  //   VolumeList in FSGlobals is renamed VolumeGroupList
   853  //
   854  //   VolumeGroup: section is created for every Volume: section
   855  //   VolumeList in VolumeGroup: section references the identically named Volume
   856  //   VirtualIPAddr in VolumeGroup: section is empty
   857  //   PrimaryPeer moves from Volume: section to VolumeGroup: section
   858  //   ReadCacheLineSize moves from FlowControl: section to VolumeGroup: section (for each Volume referencing it)
   859  //   ReadCacheWeight   moves from FlowControl: section to VolumeGroup: section (for each Volume referencing it)
   860  //
   861  //   PrimaryPeer is removed from Volume: section
   862  //   FlowControl is removed from Volume: section
   863  //
   864  //   FlowControl: section is removed
   865  //
   866  //   Generation of the name of the created VolumeGroup for each Volume
   867  //   is computed by prepending an optional prefix and appending an
   868  //   optional suffix as specified in the conf.ConfMap
   869  //
   870  // The upgrade will commence if FSGlobals section contains a VolumeList
   871  // The upgrade is unnecessary if FSGlobals section already container a VolumeGroupList
   872  //
   873  func upgradeConfMapIfNeeded(confMap conf.ConfMap) (err error) {
   874  	var (
   875  		autoVolumeGroupNamePrefix      string
   876  		autoVolumeGroupNamePrefixOK    bool
   877  		autoVolumeGroupNamePrefixSlice []string
   878  		autoVolumeGroupNameSuffix      string
   879  		autoVolumeGroupNameSuffixOK    bool
   880  		autoVolumeGroupNameSuffixSlice []string
   881  		fileDefragmentChunkDelay       conf.ConfMapOption
   882  		fileDefragmentChunkDelayOK     bool
   883  		fileDefragmentChunkSize        conf.ConfMapOption
   884  		fileDefragmentChunkSizeOK      bool
   885  		flowControl                    conf.ConfMapSection
   886  		flowControlName                conf.ConfMapOption
   887  		flowControlNameOK              bool
   888  		flowControlOK                  bool
   889  		flowControlSet                 map[string]struct{}
   890  		flowControlSetElement          string
   891  		fsGlobals                      conf.ConfMapSection
   892  		fsGlobalsOK                    bool
   893  		maxFlushSize                   conf.ConfMapOption
   894  		maxFlushSizeOK                 bool
   895  		maxFlushTime                   conf.ConfMapOption
   896  		maxFlushTimeOK                 bool
   897  		primaryPeer                    conf.ConfMapOption
   898  		primaryPeerOK                  bool
   899  		readCacheLineSize              conf.ConfMapOption
   900  		readCacheLineSizeOK            bool
   901  		readCacheWeight                conf.ConfMapOption
   902  		readCacheWeightOK              bool
   903  		transitions                    conf.ConfMapSection
   904  		transitionsOK                  bool
   905  		volume                         conf.ConfMapSection
   906  		volumeGroup                    conf.ConfMapSection
   907  		volumeGroupList                conf.ConfMapOption
   908  		volumeGroupListOK              bool
   909  		volumeOK                       bool
   910  		volumeList                     conf.ConfMapOption
   911  		volumeListOK                   bool
   912  		volumeName                     string
   913  	)
   914  
   915  	fsGlobals, fsGlobalsOK = confMap["FSGlobals"]
   916  
   917  	if !fsGlobalsOK {
   918  		err = fmt.Errorf("confMap must contain an FSGlobals section")
   919  		return
   920  	}
   921  
   922  	volumeList, volumeListOK = fsGlobals["VolumeList"]
   923  	_, volumeGroupListOK = fsGlobals["VolumeGroupList"]
   924  
   925  	if (!volumeListOK && !volumeGroupListOK) || (volumeListOK && volumeGroupListOK) {
   926  		err = fmt.Errorf("confMap must contain precisely one of FSGlobals.VolumeList or FSGlobals.VolumeGroupList")
   927  		return
   928  	}
   929  
   930  	if volumeGroupListOK {
   931  		// No need to upgrade confMap
   932  		err = nil
   933  		return
   934  	}
   935  
   936  	transitions, transitionsOK = confMap["Transitions"]
   937  	if transitionsOK {
   938  		autoVolumeGroupNamePrefixSlice, autoVolumeGroupNamePrefixOK = transitions["AutoVolumeGroupPrefix"]
   939  		if autoVolumeGroupNamePrefixOK {
   940  			switch len(autoVolumeGroupNamePrefixSlice) {
   941  			case 0:
   942  				autoVolumeGroupNamePrefix = ""
   943  			case 1:
   944  				autoVolumeGroupNamePrefix = autoVolumeGroupNamePrefixSlice[0]
   945  			default:
   946  				err = fmt.Errorf("confMap must not contain a multi-valued Transitions:AutoVolumeGroupPrefix key")
   947  				return
   948  			}
   949  		}
   950  		autoVolumeGroupNameSuffixSlice, autoVolumeGroupNameSuffixOK = transitions["AutoVolumeGroupSuffix"]
   951  		if autoVolumeGroupNameSuffixOK {
   952  			switch len(autoVolumeGroupNameSuffixSlice) {
   953  			case 0:
   954  				autoVolumeGroupNameSuffix = ""
   955  			case 1:
   956  				autoVolumeGroupNameSuffix = autoVolumeGroupNameSuffixSlice[0]
   957  			default:
   958  				err = fmt.Errorf("confMap must not contain a multi-valued Transitions:AutoVolumeGroupSuffix key")
   959  				return
   960  			}
   961  		}
   962  	} else {
   963  		autoVolumeGroupNamePrefix = ""
   964  		autoVolumeGroupNameSuffix = ""
   965  	}
   966  
   967  	volumeGroupList = make(conf.ConfMapOption, 0, len(volumeList))
   968  	for _, volumeName = range volumeList {
   969  		volumeGroupList = append(volumeGroupList, autoVolumeGroupNamePrefix+volumeName+autoVolumeGroupNameSuffix)
   970  	}
   971  	fsGlobals["VolumeGroupList"] = volumeGroupList
   972  
   973  	delete(fsGlobals, "VolumeList")
   974  
   975  	flowControlSet = make(map[string]struct{})
   976  
   977  	for _, volumeName = range volumeList {
   978  		volume, volumeOK = confMap["Volume:"+volumeName]
   979  		if !volumeOK {
   980  			err = fmt.Errorf("confMap must contain a Volume:%s section", volumeName)
   981  			return
   982  		}
   983  
   984  		primaryPeer, primaryPeerOK = volume["PrimaryPeer"]
   985  		if !primaryPeerOK || (1 < len(primaryPeer)) {
   986  			err = fmt.Errorf("confMap must contain an empty or single-valued Volume:%s.PrimaryPeer key", volumeName)
   987  			return
   988  		}
   989  
   990  		flowControlName, flowControlNameOK = volume["FlowControl"]
   991  		if !flowControlNameOK || (1 != len(flowControlName)) {
   992  			err = fmt.Errorf("confMap must contain a single-valued Volume:%s.FlowControl key", volumeName)
   993  			return
   994  		}
   995  
   996  		flowControlSet[flowControlName[0]] = struct{}{}
   997  
   998  		flowControl, flowControlOK = confMap["FlowControl:"+flowControlName[0]]
   999  		if !flowControlOK {
  1000  			err = fmt.Errorf("confMap must contain a FlowControl:%s section", flowControlName)
  1001  			return
  1002  		}
  1003  
  1004  		maxFlushSize, maxFlushSizeOK = flowControl["MaxFlushSize"]
  1005  		if !maxFlushSizeOK {
  1006  			err = fmt.Errorf("confMap must contain a FlowControl:%s.MaxFlushSize key", flowControlName[0])
  1007  			return
  1008  		}
  1009  
  1010  		maxFlushTime, maxFlushTimeOK = flowControl["MaxFlushTime"]
  1011  		if !maxFlushTimeOK {
  1012  			err = fmt.Errorf("confMap must contain a FlowControl:%s.MaxFlushTime key", flowControlName[0])
  1013  			return
  1014  		}
  1015  
  1016  		fileDefragmentChunkSize, fileDefragmentChunkSizeOK = flowControl["FileDefragmentChunkSize"]
  1017  		fileDefragmentChunkDelay, fileDefragmentChunkDelayOK = flowControl["FileDefragmentChunkDelay"]
  1018  
  1019  		readCacheLineSize, readCacheLineSizeOK = flowControl["ReadCacheLineSize"]
  1020  		if !readCacheLineSizeOK {
  1021  			err = fmt.Errorf("confMap must contain a FlowControl:%s.ReadCacheLineSize key", flowControlName[0])
  1022  			return
  1023  		}
  1024  
  1025  		readCacheWeight, readCacheWeightOK = flowControl["ReadCacheWeight"]
  1026  		if !readCacheWeightOK {
  1027  			err = fmt.Errorf("confMap must contain a FlowControl:%s.ReadCacheWeight key", flowControlName[0])
  1028  			return
  1029  		}
  1030  
  1031  		volumeGroup = make(conf.ConfMapSection)
  1032  
  1033  		volumeGroup["VolumeList"] = []string{volumeName}
  1034  		volumeGroup["VirtualIPAddr"] = []string{}
  1035  		volumeGroup["PrimaryPeer"] = primaryPeer
  1036  		volumeGroup["ReadCacheLineSize"] = readCacheLineSize
  1037  		volumeGroup["ReadCacheWeight"] = readCacheWeight
  1038  
  1039  		confMap["VolumeGroup:"+autoVolumeGroupNamePrefix+volumeName+autoVolumeGroupNameSuffix] = volumeGroup
  1040  
  1041  		volume["MaxFlushSize"] = maxFlushSize
  1042  		volume["MaxFlushTime"] = maxFlushTime
  1043  
  1044  		if fileDefragmentChunkSizeOK {
  1045  			volume["FileDefragmentChunkSize"] = fileDefragmentChunkSize
  1046  		}
  1047  		if fileDefragmentChunkDelayOK {
  1048  			volume["FileDefragmentChunkDelay"] = fileDefragmentChunkDelay
  1049  		}
  1050  
  1051  		delete(volume, "PrimaryPeer")
  1052  		delete(volume, "FlowControl")
  1053  	}
  1054  
  1055  	for flowControlSetElement = range flowControlSet {
  1056  		delete(confMap, "FlowControl:"+flowControlSetElement)
  1057  	}
  1058  
  1059  	err = nil
  1060  	return
  1061  }
  1062  
  1063  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) Up(confMap conf.ConfMap) (err error) {
  1064  	return logger.Up(confMap)
  1065  }
  1066  
  1067  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeGroupCreated(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) {
  1068  	return nil
  1069  }
  1070  
  1071  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeGroupMoved(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) {
  1072  	return nil
  1073  }
  1074  
  1075  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeGroupDestroyed(confMap conf.ConfMap, volumeGroupName string) (err error) {
  1076  	return nil
  1077  }
  1078  
  1079  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeCreated(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) {
  1080  	return nil
  1081  }
  1082  
  1083  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeMoved(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) {
  1084  	return nil
  1085  }
  1086  
  1087  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeDestroyed(confMap conf.ConfMap, volumeName string) (err error) {
  1088  	return nil
  1089  }
  1090  
  1091  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) ServeVolume(confMap conf.ConfMap, volumeName string) (err error) {
  1092  	return nil
  1093  }
  1094  
  1095  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) UnserveVolume(confMap conf.ConfMap, volumeName string) (err error) {
  1096  	return nil
  1097  }
  1098  
  1099  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) VolumeToBeUnserved(confMap conf.ConfMap, volumeName string) (err error) {
  1100  	return nil
  1101  }
  1102  
  1103  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) SignaledStart(confMap conf.ConfMap) (err error) {
  1104  	return logger.SignaledStart(confMap)
  1105  }
  1106  
  1107  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) SignaledFinish(confMap conf.ConfMap) (err error) {
  1108  	return logger.SignaledFinish(confMap)
  1109  }
  1110  
  1111  func (loggerCallbacksInterface *loggerCallbacksInterfaceStruct) Down(confMap conf.ConfMap) (err error) {
  1112  	return logger.Down(confMap)
  1113  }
  1114  
  1115  func dumpGlobals(indent string) {
  1116  	var (
  1117  		registrationItem        *registrationItemStruct
  1118  		registrationListElement *list.Element
  1119  		volume                  *volumeStruct
  1120  		volumeGroup             *volumeGroupStruct
  1121  		volumeGroupName         string
  1122  		volumeName              string
  1123  	)
  1124  
  1125  	registrationListElement = globals.registrationList.Front()
  1126  
  1127  	if nil == registrationListElement {
  1128  		fmt.Printf("%sregistrationList: <empty>\n", indent)
  1129  	} else {
  1130  		fmt.Printf("%sregistrationList:", indent)
  1131  		for nil != registrationListElement {
  1132  			registrationItem = registrationListElement.Value.(*registrationItemStruct)
  1133  			fmt.Printf(" %s", registrationItem.packageName)
  1134  			registrationListElement = registrationListElement.Next()
  1135  		}
  1136  		fmt.Println()
  1137  	}
  1138  
  1139  	if 0 == len(globals.currentConfMapDelta.volumeGroupList) {
  1140  		fmt.Printf("%svolumeGroupList: <empty>\n", indent)
  1141  	} else {
  1142  		fmt.Printf("%svolumeGroupList:\n", indent)
  1143  		for volumeGroupName, volumeGroup = range globals.currentConfMapDelta.volumeGroupList {
  1144  			fmt.Printf("%s  %+v [volumeList:", indent, volumeGroup)
  1145  			for volumeName = range volumeGroup.volumeList {
  1146  				fmt.Printf(" %s", volumeName)
  1147  			}
  1148  			fmt.Printf("]\n")
  1149  		}
  1150  	}
  1151  
  1152  	if 0 == len(globals.currentConfMapDelta.servedVolumeGroupList) {
  1153  		fmt.Printf("%sservedVolumeGroupList: <empty>\n", indent)
  1154  	} else {
  1155  		fmt.Printf("%sservedVolumeGroupList:", indent)
  1156  		for volumeGroupName = range globals.currentConfMapDelta.servedVolumeGroupList {
  1157  			fmt.Printf(" %s", volumeGroupName)
  1158  		}
  1159  		fmt.Println()
  1160  	}
  1161  
  1162  	if 0 == len(globals.currentConfMapDelta.remoteVolumeGroupList) {
  1163  		fmt.Printf("%sremoteVolumeGroupList: <empty>\n", indent)
  1164  	} else {
  1165  		fmt.Printf("%sremoteVolumeGroupList:", indent)
  1166  		for volumeGroupName = range globals.currentConfMapDelta.remoteVolumeGroupList {
  1167  			fmt.Printf(" %s", volumeGroupName)
  1168  		}
  1169  		fmt.Println()
  1170  	}
  1171  
  1172  	if 0 == len(globals.currentConfMapDelta.createdVolumeGroupList) {
  1173  		fmt.Printf("%screatedVolumeGroupList: <empty>\n", indent)
  1174  	} else {
  1175  		fmt.Printf("%screatedVolumeGroupList:", indent)
  1176  		for volumeGroupName = range globals.currentConfMapDelta.createdVolumeGroupList {
  1177  			fmt.Printf(" %s", volumeGroupName)
  1178  		}
  1179  		fmt.Println()
  1180  	}
  1181  
  1182  	if 0 == len(globals.currentConfMapDelta.movedVolumeGroupList) {
  1183  		fmt.Printf("%smovedVolumeGroupList: <empty>\n", indent)
  1184  	} else {
  1185  		fmt.Printf("%smovedVolumeGroupList:", indent)
  1186  		for volumeGroupName = range globals.currentConfMapDelta.movedVolumeGroupList {
  1187  			fmt.Printf(" %s", volumeGroupName)
  1188  		}
  1189  		fmt.Println()
  1190  	}
  1191  
  1192  	if 0 == len(globals.currentConfMapDelta.destroyedVolumeGroupList) {
  1193  		fmt.Printf("%sdestroyedVolumeGroupList: <empty>\n", indent)
  1194  	} else {
  1195  		fmt.Printf("%sdestroyedVolumeGroupList:", indent)
  1196  		for volumeGroupName = range globals.currentConfMapDelta.destroyedVolumeGroupList {
  1197  			fmt.Printf(" %s", volumeGroupName)
  1198  		}
  1199  		fmt.Println()
  1200  	}
  1201  
  1202  	if 0 == len(globals.currentConfMapDelta.volumeList) {
  1203  		fmt.Printf("%svolumeList: <empty>\n", indent)
  1204  	} else {
  1205  		fmt.Printf("%svolumeList:\n", indent)
  1206  		for volumeName, volume = range globals.currentConfMapDelta.volumeList {
  1207  			fmt.Printf("%s  %+v [volumeGroup: %s]\n", indent, volume, volume.volumeGroup.name)
  1208  		}
  1209  	}
  1210  
  1211  	if 0 == len(globals.currentConfMapDelta.servedVolumeList) {
  1212  		fmt.Printf("%sservedVolumeList: <empty>\n", indent)
  1213  	} else {
  1214  		fmt.Printf("%sservedVolumeList:", indent)
  1215  		for volumeName = range globals.currentConfMapDelta.servedVolumeList {
  1216  			fmt.Printf(" %s", volumeName)
  1217  		}
  1218  		fmt.Println()
  1219  	}
  1220  
  1221  	if 0 == len(globals.currentConfMapDelta.remoteVolumeList) {
  1222  		fmt.Printf("%sremoteVolumeList: <empty>\n", indent)
  1223  	} else {
  1224  		fmt.Printf("%sremoteVolumeList:", indent)
  1225  		for volumeName = range globals.currentConfMapDelta.remoteVolumeList {
  1226  			fmt.Printf(" %s", volumeName)
  1227  		}
  1228  		fmt.Println()
  1229  	}
  1230  
  1231  	if 0 == len(globals.currentConfMapDelta.createdVolumeList) {
  1232  		fmt.Printf("%screatedVolumeList: <empty>\n", indent)
  1233  	} else {
  1234  		fmt.Printf("%screatedVolumeList:", indent)
  1235  		for volumeName = range globals.currentConfMapDelta.createdVolumeList {
  1236  			fmt.Printf(" %s", volumeName)
  1237  		}
  1238  		fmt.Println()
  1239  	}
  1240  
  1241  	if 0 == len(globals.currentConfMapDelta.movedVolumeList) {
  1242  		fmt.Printf("%smovedVolumeList: <empty>\n", indent)
  1243  	} else {
  1244  		fmt.Printf("%smovedVolumeList:", indent)
  1245  		for volumeName = range globals.currentConfMapDelta.movedVolumeList {
  1246  			fmt.Printf(" %s", volumeName)
  1247  		}
  1248  		fmt.Println()
  1249  	}
  1250  
  1251  	if 0 == len(globals.currentConfMapDelta.destroyedVolumeList) {
  1252  		fmt.Printf("%sdestroyedVolumeList: <empty>\n", indent)
  1253  	} else {
  1254  		fmt.Printf("%sdestroyedVolumeList:", indent)
  1255  		for volumeName = range globals.currentConfMapDelta.destroyedVolumeList {
  1256  			fmt.Printf(" %s", volumeName)
  1257  		}
  1258  		fmt.Println()
  1259  	}
  1260  
  1261  	if 0 == len(globals.currentConfMapDelta.toStopServingVolumeList) {
  1262  		fmt.Printf("%stoStopServingVolumeList: <empty>\n", indent)
  1263  	} else {
  1264  		fmt.Printf("%stoStopServingVolumeList:", indent)
  1265  		for volumeName = range globals.currentConfMapDelta.toStopServingVolumeList {
  1266  			fmt.Printf(" %s", volumeName)
  1267  		}
  1268  		fmt.Println()
  1269  	}
  1270  
  1271  	if 0 == len(globals.currentConfMapDelta.toStartServingVolumeList) {
  1272  		fmt.Printf("%stoStartServingVolumeList: <empty>\n", indent)
  1273  	} else {
  1274  		fmt.Printf("%stoStartServingVolumeList:", indent)
  1275  		for volumeName = range globals.currentConfMapDelta.toStartServingVolumeList {
  1276  			fmt.Printf(" %s", volumeName)
  1277  		}
  1278  		fmt.Println()
  1279  	}
  1280  }