55package pool
66
77import (
8+ "container/list"
89"io/ioutil"
910"os"
1011"path"
@@ -34,9 +35,8 @@ const (
3435type Manager struct {
3536cfg * Config
3637mu * sync.Mutex
38+ fsManagerList * list.List
3739fsManagerPool map [string ]FSManager
38- fsManager FSManager
39- oldFsManager FSManager
4040runner runners.Runner
4141blockDeviceTypes map [string ]string
4242}
@@ -58,6 +58,7 @@ func NewPoolManager(cfg *Config, runner runners.Runner) *Manager {
5858fsManagerPool :make (map [string ]FSManager ),
5959runner :runner ,
6060blockDeviceTypes :make (map [string ]string ),
61+ fsManagerList :list .New (),
6162}
6263}
6364
@@ -68,24 +69,56 @@ func (pm *Manager) Reload(cfg Config) error {
6869return pm .ReloadPools ()
6970}
7071
71- //Active returns the activefilesystem pool manager.
72- func (pm * Manager )Active () FSManager {
73- return pm .fsManager
72+ //SetActive sets a new active pool manager element .
73+ func (pm * Manager )SetActive ( element * list. Element ) {
74+ pm .fsManagerList . MoveToFront ( element )
7475}
7576
76- // SetActive sets a new active pool manager.
77- func (pm * Manager )SetActive (active FSManager ) {
78- pm .fsManager = active
77+ // Active returns the active storage pool manager.
78+ func (pm * Manager )Active ()FSManager {
79+ active := pm .fsManagerList .Front ()
80+
81+ if active == nil || active .Value == nil {
82+ return nil
83+ }
84+
85+ return pm .getFSManager (active .Value .(string ))
7986}
8087
81- // Oldest returns the oldest filesystem pool manager.
82- func (pm * Manager )Oldest ()FSManager {
83- return pm .oldFsManager
88+ func (pm * Manager )getFSManager (pool string )FSManager {
89+ pm .mu .Lock ()
90+ fsm := pm .fsManagerPool [pool ]
91+ pm .mu .Unlock ()
92+
93+ return fsm
8494}
8595
86- // SetOldest sets a pool manager to update.
87- func (pm * Manager )SetOldest (pool FSManager ) {
88- pm .oldFsManager = pool
96+ // GetPoolToUpdate returns the element to update.
97+ func (pm * Manager )GetPoolToUpdate ()* list.Element {
98+ for element := pm .fsManagerList .Back ();element != nil ;element = element .Prev () {
99+ if element .Value == nil {
100+ return nil
101+ }
102+
103+ // The active pool cannot be updated as it leads to downtime.
104+ if element == pm .fsManagerList .Front () {
105+ return nil
106+ }
107+
108+ fsm := pm .getFSManager (element .Value .(string ))
109+
110+ clones ,err := fsm .ListClonesNames ()
111+ if err != nil {
112+ log .Err ("failed to list clones" ,err )
113+ return nil
114+ }
115+
116+ if len (clones )== 0 {
117+ return element
118+ }
119+ }
120+
121+ return nil
89122}
90123
91124// GetFSManager returns a filesystem manager by name if exists.
@@ -130,24 +163,14 @@ func (pm *Manager) ReloadPools() error {
130163fsPools := pm .examineEntries (entries )
131164
132165if len (fsPools )== 0 {
133- return errors .New ("no available filesystem pools" )
134- }
135-
136- active ,old := pm .detectWorkingPools (fsPools )
137-
138- if active == nil {
139- return errors .New ("active pool not found: make sure it exists" )
166+ return errors .New ("no available pools" )
140167}
141168
142169pm .mu .Lock ()
143-
144170pm .fsManagerPool = fsPools
145- pm .SetActive (active )
146- pm .SetOldest (old )
147-
148171pm .mu .Unlock ()
149172
150- log .Msg ("AvailableFS pools: " ,pm .describeAvailablePools ())
173+ log .Msg ("Availablestorage pools: " ,pm .describeAvailablePools ())
151174log .Msg ("Active pool: " ,pm .Active ().Pool ().Name )
152175
153176return nil
@@ -208,6 +231,13 @@ func (pm *Manager) examineEntries(entries []os.FileInfo) map[string]FSManager {
208231
209232// TODO(akartasov): extract pool name.
210233fsManagers [entry .Name ()]= fsm
234+
235+ if pm .Active ()== nil || pm .Active ().Pool ().DSA .Before (pool .DSA ) {
236+ pm .fsManagerList .PushFront (fsm .Pool ().Name )
237+ continue
238+ }
239+
240+ pm .fsManagerList .PushBack (fsm .Pool ().Name )
211241}
212242
213243return fsManagers
@@ -226,33 +256,6 @@ func (pm *Manager) reloadBlockDevices() error {
226256return nil
227257}
228258
229- func (pm * Manager )detectWorkingPools (fsm map [string ]FSManager ) (FSManager ,FSManager ) {
230- var fsManager ,old FSManager
231-
232- for _ ,manager := range fsm {
233- if fsManager == nil {
234- fsManager = manager
235- continue
236- }
237-
238- if fsManager .Pool ().DSA .Before (manager .Pool ().DSA ) {
239- if old == nil {
240- old = fsManager
241- }
242-
243- fsManager = manager
244-
245- continue
246- }
247-
248- if old == nil || manager .Pool ().DSA .Before (old .Pool ().DSA ) {
249- old = manager
250- }
251- }
252-
253- return fsManager ,old
254- }
255-
256259func extractDataStateAt (dataPath string ) (* time.Time ,error ) {
257260marker := dbmarker .NewMarker (dataPath )
258261
@@ -294,13 +297,14 @@ func (pm *Manager) getFSInfo(path string) (string, error) {
294297func (pm * Manager )describeAvailablePools () []string {
295298availablePools := []string {}
296299
297- pm .mu .Lock ()
300+ for el := pm .fsManagerList .Front ();el != nil ;el = el .Next () {
301+ if el .Value == nil {
302+ log .Err ("empty element: skip listing" )
303+ continue
304+ }
298305
299- for _ ,fsm := range pm .fsManagerPool {
300- availablePools = append (availablePools ,fsm .Pool ().DataDir ())
306+ availablePools = append (availablePools ,el .Value .(string ))
301307}
302308
303- pm .mu .Unlock ()
304-
305309return availablePools
306310}