github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/volume/store/store.go (about) 1 package store 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "net" 7 "os" 8 "path/filepath" 9 "sync" 10 "time" 11 12 "github.com/pkg/errors" 13 14 "github.com/Sirupsen/logrus" 15 "github.com/boltdb/bolt" 16 "github.com/docker/docker/pkg/locker" 17 "github.com/docker/docker/volume" 18 "github.com/docker/docker/volume/drivers" 19 ) 20 21 const ( 22 volumeDataDir = "volumes" 23 volumeBucketName = "volumes" 24 ) 25 26 type volumeMetadata struct { 27 Name string 28 Labels map[string]string 29 Options map[string]string 30 } 31 32 type volumeWrapper struct { 33 volume.Volume 34 labels map[string]string 35 scope string 36 options map[string]string 37 } 38 39 func (v volumeWrapper) Options() map[string]string { 40 options := map[string]string{} 41 for key, value := range v.options { 42 options[key] = value 43 } 44 return options 45 } 46 47 func (v volumeWrapper) Labels() map[string]string { 48 return v.labels 49 } 50 51 func (v volumeWrapper) Scope() string { 52 return v.scope 53 } 54 55 func (v volumeWrapper) CachedPath() string { 56 if vv, ok := v.Volume.(interface { 57 CachedPath() string 58 }); ok { 59 return vv.CachedPath() 60 } 61 return v.Volume.Path() 62 } 63 64 // New initializes a VolumeStore to keep 65 // reference counting of volumes in the system. 66 func New(rootPath string) (*VolumeStore, error) { 67 vs := &VolumeStore{ 68 locks: &locker.Locker{}, 69 names: make(map[string]volume.Volume), 70 refs: make(map[string]map[string]struct{}), 71 labels: make(map[string]map[string]string), 72 options: make(map[string]map[string]string), 73 } 74 75 if rootPath != "" { 76 // initialize metadata store 77 volPath := filepath.Join(rootPath, volumeDataDir) 78 if err := os.MkdirAll(volPath, 750); err != nil { 79 return nil, err 80 } 81 82 dbPath := filepath.Join(volPath, "metadata.db") 83 84 var err error 85 vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) 86 if err != nil { 87 return nil, errors.Wrap(err, "error while opening volume store metadata database") 88 } 89 90 // initialize volumes bucket 91 if err := vs.db.Update(func(tx *bolt.Tx) error { 92 if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil { 93 return errors.Wrap(err, "error while setting up volume store metadata database") 94 } 95 96 return nil 97 }); err != nil { 98 return nil, err 99 } 100 } 101 102 return vs, nil 103 } 104 105 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 106 s.globalLock.RLock() 107 v, exists := s.names[name] 108 s.globalLock.RUnlock() 109 return v, exists 110 } 111 112 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 113 name := v.Name() 114 115 s.globalLock.Lock() 116 s.names[name] = v 117 if len(ref) > 0 { 118 if s.refs[name] == nil { 119 s.refs[name] = make(map[string]struct{}) 120 } 121 s.refs[name][ref] = struct{}{} 122 } 123 s.globalLock.Unlock() 124 } 125 126 // hasRef returns true if the given name has at least one ref. 127 // Callers of this function are expected to hold the name lock. 128 func (s *VolumeStore) hasRef(name string) bool { 129 s.globalLock.RLock() 130 l := len(s.refs[name]) 131 s.globalLock.RUnlock() 132 return l > 0 133 } 134 135 // getRefs gets the list of refs for a given name 136 // Callers of this function are expected to hold the name lock. 137 func (s *VolumeStore) getRefs(name string) []string { 138 s.globalLock.RLock() 139 defer s.globalLock.RUnlock() 140 141 refs := make([]string, 0, len(s.refs[name])) 142 for r := range s.refs[name] { 143 refs = append(refs, r) 144 } 145 146 return refs 147 } 148 149 // Purge allows the cleanup of internal data on docker in case 150 // the internal data is out of sync with volumes driver plugins. 151 func (s *VolumeStore) Purge(name string) { 152 s.globalLock.Lock() 153 delete(s.names, name) 154 delete(s.refs, name) 155 delete(s.labels, name) 156 delete(s.options, name) 157 s.globalLock.Unlock() 158 } 159 160 // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts 161 type VolumeStore struct { 162 // locks ensures that only one action is being performed on a particular volume at a time without locking the entire store 163 // since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes. 164 locks *locker.Locker 165 // globalLock is used to protect access to mutable structures used by the store object 166 globalLock sync.RWMutex 167 // names stores the volume name -> volume relationship. 168 // This is used for making lookups faster so we don't have to probe all drivers 169 names map[string]volume.Volume 170 // refs stores the volume name and the list of things referencing it 171 refs map[string]map[string]struct{} 172 // labels stores volume labels for each volume 173 labels map[string]map[string]string 174 // options stores volume options for each volume 175 options map[string]map[string]string 176 db *bolt.DB 177 } 178 179 // List proxies to all registered volume drivers to get the full list of volumes 180 // If a driver returns a volume that has name which conflicts with another volume from a different driver, 181 // the first volume is chosen and the conflicting volume is dropped. 182 func (s *VolumeStore) List() ([]volume.Volume, []string, error) { 183 vols, warnings, err := s.list() 184 if err != nil { 185 return nil, nil, &OpErr{Err: err, Op: "list"} 186 } 187 var out []volume.Volume 188 189 for _, v := range vols { 190 name := normaliseVolumeName(v.Name()) 191 192 s.locks.Lock(name) 193 storedV, exists := s.getNamed(name) 194 // Note: it's not safe to populate the cache here because the volume may have been 195 // deleted before we acquire a lock on its name 196 if exists && storedV.DriverName() != v.DriverName() { 197 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 198 s.locks.Unlock(v.Name()) 199 continue 200 } 201 202 out = append(out, v) 203 s.locks.Unlock(v.Name()) 204 } 205 return out, warnings, nil 206 } 207 208 // list goes through each volume driver and asks for its list of volumes. 209 func (s *VolumeStore) list() ([]volume.Volume, []string, error) { 210 var ( 211 ls []volume.Volume 212 warnings []string 213 ) 214 215 drivers, err := volumedrivers.GetAllDrivers() 216 if err != nil { 217 return nil, nil, err 218 } 219 220 type vols struct { 221 vols []volume.Volume 222 err error 223 driverName string 224 } 225 chVols := make(chan vols, len(drivers)) 226 227 for _, vd := range drivers { 228 go func(d volume.Driver) { 229 vs, err := d.List() 230 if err != nil { 231 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 232 return 233 } 234 for i, v := range vs { 235 s.globalLock.RLock() 236 vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]} 237 s.globalLock.RUnlock() 238 } 239 240 chVols <- vols{vols: vs} 241 }(vd) 242 } 243 244 badDrivers := make(map[string]struct{}) 245 for i := 0; i < len(drivers); i++ { 246 vs := <-chVols 247 248 if vs.err != nil { 249 warnings = append(warnings, vs.err.Error()) 250 badDrivers[vs.driverName] = struct{}{} 251 logrus.Warn(vs.err) 252 } 253 ls = append(ls, vs.vols...) 254 } 255 256 if len(badDrivers) > 0 { 257 s.globalLock.RLock() 258 for _, v := range s.names { 259 if _, exists := badDrivers[v.DriverName()]; exists { 260 ls = append(ls, v) 261 } 262 } 263 s.globalLock.RUnlock() 264 } 265 return ls, warnings, nil 266 } 267 268 // CreateWithRef creates a volume with the given name and driver and stores the ref 269 // This ensures there's no race between creating a volume and then storing a reference. 270 func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) { 271 name = normaliseVolumeName(name) 272 s.locks.Lock(name) 273 defer s.locks.Unlock(name) 274 275 v, err := s.create(name, driverName, opts, labels) 276 if err != nil { 277 return nil, &OpErr{Err: err, Name: name, Op: "create"} 278 } 279 280 s.setNamed(v, ref) 281 return v, nil 282 } 283 284 // Create creates a volume with the given name and driver. 285 // This is just like CreateWithRef() except we don't store a reference while holding the lock. 286 func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 287 return s.CreateWithRef(name, driverName, "", opts, labels) 288 } 289 290 // checkConflict checks the local cache for name collisions with the passed in name, 291 // for existing volumes with the same name but in a different driver. 292 // This is used by `Create` as a best effort to prevent name collisions for volumes. 293 // If a matching volume is found that is not a conflict that is returned so the caller 294 // does not need to perform an additional lookup. 295 // When no matching volume is found, both returns will be nil 296 // 297 // Note: This does not probe all the drivers for name collisions because v1 plugins 298 // are very slow, particularly if the plugin is down, and cause other issues, 299 // particularly around locking the store. 300 // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially 301 // use a connect timeout for this kind of check to ensure we aren't blocking for a 302 // long time. 303 func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, error) { 304 // check the local cache 305 v, _ := s.getNamed(name) 306 if v == nil { 307 return nil, nil 308 } 309 310 vDriverName := v.DriverName() 311 var conflict bool 312 if driverName != "" && vDriverName != driverName { 313 conflict = true 314 } 315 316 // let's check if the found volume ref 317 // is stale by checking with the driver if it still exists 318 exists, err := volumeExists(v) 319 if err != nil { 320 return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err) 321 } 322 323 if exists { 324 if conflict { 325 return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name) 326 } 327 return v, nil 328 } 329 330 if s.hasRef(v.Name()) { 331 // Containers are referencing this volume but it doesn't seem to exist anywhere. 332 // Return a conflict error here, the user can fix this with `docker volume rm -f` 333 return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName) 334 } 335 336 // doesn't exist, so purge it from the cache 337 s.Purge(name) 338 return nil, nil 339 } 340 341 // volumeExists returns if the volume is still present in the driver. 342 // An error is returned if there was an issue communicating with the driver. 343 func volumeExists(v volume.Volume) (bool, error) { 344 vd, err := volumedrivers.GetDriver(v.DriverName()) 345 if err != nil { 346 return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName()) 347 } 348 exists, err := vd.Get(v.Name()) 349 if err != nil { 350 err = errors.Cause(err) 351 if _, ok := err.(net.Error); ok { 352 return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName()) 353 } 354 355 // At this point, the error could be anything from the driver, such as "no such volume" 356 // Let's not check an error here, and instead check if the driver returned a volume 357 } 358 if exists == nil { 359 return false, nil 360 } 361 return true, nil 362 } 363 364 // create asks the given driver to create a volume with the name/opts. 365 // If a volume with the name is already known, it will ask the stored driver for the volume. 366 // If the passed in driver name does not match the driver name which is stored 367 // for the given volume name, an error is returned after checking if the reference is stale. 368 // If the reference is stale, it will be purged and this create can continue. 369 // It is expected that callers of this function hold any necessary locks. 370 func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 371 // Validate the name in a platform-specific manner 372 valid, err := volume.IsVolumeNameValid(name) 373 if err != nil { 374 return nil, err 375 } 376 if !valid { 377 return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"} 378 } 379 380 v, err := s.checkConflict(name, driverName) 381 if err != nil { 382 return nil, err 383 } 384 385 if v != nil { 386 return v, nil 387 } 388 389 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 390 if driverName == "" { 391 v, _ := s.getVolume(name) 392 if v != nil { 393 return v, nil 394 } 395 } 396 397 vd, err := volumedrivers.CreateDriver(driverName) 398 399 if err != nil { 400 return nil, &OpErr{Op: "create", Name: name, Err: err} 401 } 402 403 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 404 405 if v, _ := vd.Get(name); v != nil { 406 return v, nil 407 } 408 v, err = vd.Create(name, opts) 409 if err != nil { 410 return nil, err 411 } 412 s.globalLock.Lock() 413 s.labels[name] = labels 414 s.options[name] = opts 415 s.refs[name] = make(map[string]struct{}) 416 s.globalLock.Unlock() 417 418 if s.db != nil { 419 metadata := &volumeMetadata{ 420 Name: name, 421 Labels: labels, 422 Options: opts, 423 } 424 425 volData, err := json.Marshal(metadata) 426 if err != nil { 427 return nil, err 428 } 429 430 if err := s.db.Update(func(tx *bolt.Tx) error { 431 b := tx.Bucket([]byte(volumeBucketName)) 432 err := b.Put([]byte(name), volData) 433 return err 434 }); err != nil { 435 return nil, errors.Wrap(err, "error while persisting volume metadata") 436 } 437 } 438 439 return volumeWrapper{v, labels, vd.Scope(), opts}, nil 440 } 441 442 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 443 // This is just like Get(), but we store the reference while holding the lock. 444 // This makes sure there are no races between checking for the existence of a volume and adding a reference for it 445 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 446 name = normaliseVolumeName(name) 447 s.locks.Lock(name) 448 defer s.locks.Unlock(name) 449 450 vd, err := volumedrivers.GetDriver(driverName) 451 if err != nil { 452 return nil, &OpErr{Err: err, Name: name, Op: "get"} 453 } 454 455 v, err := vd.Get(name) 456 if err != nil { 457 return nil, &OpErr{Err: err, Name: name, Op: "get"} 458 } 459 460 s.setNamed(v, ref) 461 462 s.globalLock.RLock() 463 defer s.globalLock.RUnlock() 464 return volumeWrapper{v, s.labels[name], vd.Scope(), s.options[name]}, nil 465 } 466 467 // Get looks if a volume with the given name exists and returns it if so 468 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 469 name = normaliseVolumeName(name) 470 s.locks.Lock(name) 471 defer s.locks.Unlock(name) 472 473 v, err := s.getVolume(name) 474 if err != nil { 475 return nil, &OpErr{Err: err, Name: name, Op: "get"} 476 } 477 s.setNamed(v, "") 478 return v, nil 479 } 480 481 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 482 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 483 // it is expected that callers of this function hold any necessary locks 484 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 485 labels := map[string]string{} 486 options := map[string]string{} 487 488 if s.db != nil { 489 // get meta 490 if err := s.db.Update(func(tx *bolt.Tx) error { 491 b := tx.Bucket([]byte(volumeBucketName)) 492 data := b.Get([]byte(name)) 493 494 if string(data) == "" { 495 return nil 496 } 497 498 var meta volumeMetadata 499 buf := bytes.NewBuffer(data) 500 501 if err := json.NewDecoder(buf).Decode(&meta); err != nil { 502 return err 503 } 504 labels = meta.Labels 505 options = meta.Options 506 507 return nil 508 }); err != nil { 509 return nil, err 510 } 511 } 512 513 logrus.Debugf("Getting volume reference for name: %s", name) 514 s.globalLock.RLock() 515 v, exists := s.names[name] 516 s.globalLock.RUnlock() 517 if exists { 518 vd, err := volumedrivers.GetDriver(v.DriverName()) 519 if err != nil { 520 return nil, err 521 } 522 vol, err := vd.Get(name) 523 if err != nil { 524 return nil, err 525 } 526 return volumeWrapper{vol, labels, vd.Scope(), options}, nil 527 } 528 529 logrus.Debugf("Probing all drivers for volume with name: %s", name) 530 drivers, err := volumedrivers.GetAllDrivers() 531 if err != nil { 532 return nil, err 533 } 534 535 for _, d := range drivers { 536 v, err := d.Get(name) 537 if err != nil { 538 continue 539 } 540 541 return volumeWrapper{v, labels, d.Scope(), options}, nil 542 } 543 return nil, errNoSuchVolume 544 } 545 546 // Remove removes the requested volume. A volume is not removed if it has any refs 547 func (s *VolumeStore) Remove(v volume.Volume) error { 548 name := normaliseVolumeName(v.Name()) 549 s.locks.Lock(name) 550 defer s.locks.Unlock(name) 551 552 if s.hasRef(name) { 553 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)} 554 } 555 556 vd, err := volumedrivers.RemoveDriver(v.DriverName()) 557 if err != nil { 558 return &OpErr{Err: err, Name: vd.Name(), Op: "remove"} 559 } 560 561 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 562 vol := unwrapVolume(v) 563 if err := vd.Remove(vol); err != nil { 564 return &OpErr{Err: err, Name: name, Op: "remove"} 565 } 566 567 s.Purge(name) 568 return nil 569 } 570 571 // Dereference removes the specified reference to the volume 572 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 573 name := v.Name() 574 575 s.locks.Lock(name) 576 defer s.locks.Unlock(name) 577 578 s.globalLock.Lock() 579 defer s.globalLock.Unlock() 580 581 if s.refs[name] != nil { 582 delete(s.refs[name], ref) 583 } 584 } 585 586 // Refs gets the current list of refs for the given volume 587 func (s *VolumeStore) Refs(v volume.Volume) []string { 588 name := v.Name() 589 590 s.locks.Lock(name) 591 defer s.locks.Unlock(name) 592 593 return s.getRefs(name) 594 } 595 596 // FilterByDriver returns the available volumes filtered by driver name 597 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 598 vd, err := volumedrivers.GetDriver(name) 599 if err != nil { 600 return nil, &OpErr{Err: err, Name: name, Op: "list"} 601 } 602 ls, err := vd.List() 603 if err != nil { 604 return nil, &OpErr{Err: err, Name: name, Op: "list"} 605 } 606 for i, v := range ls { 607 options := map[string]string{} 608 s.globalLock.RLock() 609 for key, value := range s.options[v.Name()] { 610 options[key] = value 611 } 612 ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope(), options} 613 s.globalLock.RUnlock() 614 } 615 return ls, nil 616 } 617 618 // FilterByUsed returns the available volumes filtered by if they are in use or not. 619 // `used=true` returns only volumes that are being used, while `used=false` returns 620 // only volumes that are not being used. 621 func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume { 622 return s.filter(vols, func(v volume.Volume) bool { 623 s.locks.Lock(v.Name()) 624 hasRef := s.hasRef(v.Name()) 625 s.locks.Unlock(v.Name()) 626 if used == hasRef { 627 return true 628 } 629 return false 630 }) 631 } 632 633 // filterFunc defines a function to allow filter volumes in the store 634 type filterFunc func(vol volume.Volume) bool 635 636 // filter returns the available volumes filtered by a filterFunc function 637 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 638 var ls []volume.Volume 639 for _, v := range vols { 640 if f(v) { 641 ls = append(ls, v) 642 } 643 } 644 return ls 645 } 646 647 func unwrapVolume(v volume.Volume) volume.Volume { 648 if vol, ok := v.(volumeWrapper); ok { 649 return vol.Volume 650 } 651 652 return v 653 }