github.com/swiftstack/proxyfs@v0.0.0-20201223034610-5434d919416e/transitions/api_internal.go (about)

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