diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp index 4b8762caa2..45897c4223 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp @@ -15,6 +15,7 @@ Dependency::Dependency(Package* package) : fPackage(package), + fFamily(NULL), fResolvable(NULL), fName(NULL), fVersion(NULL), diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h index e2027f8d1b..142b274dca 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.h +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h @@ -13,6 +13,7 @@ #include +class DependencyFamily; class Package; class Resolvable; class Version; @@ -34,21 +35,41 @@ public: // version is optional; object takes over // ownership + void SetFamily(DependencyFamily* family) + { fFamily = family; } + DependencyFamily* Family() const + { return fFamily; } + void SetResolvable(::Resolvable* resolvable) { fResolvable = resolvable; } ::Resolvable* Resolvable() const { return fResolvable; } + const char* Name() const { return fName; } + private: Package* fPackage; + DependencyFamily* fFamily; ::Resolvable* fResolvable; char* fName; Version* fVersion; BPackageResolvableOperator fVersionOperator; + +public: // conceptually package private + DoublyLinkedListLink fFamilyListLink; + DoublyLinkedListLink fResolvableListLink; }; typedef DoublyLinkedList DependencyList; +typedef DoublyLinkedList > FamilyDependencyList; + +typedef DoublyLinkedList > ResolvableDependencyList; + #endif // DEPENDENCY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h new file mode 100644 index 0000000000..3971bc07f7 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h @@ -0,0 +1,97 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEPENDENCY_FAMILY_H +#define DEPENDENCY_FAMILY_H + + +#include +#include + +#include "Dependency.h" + + +class DependencyFamily { +public: + void AddDependency(Dependency* dependency); + void RemoveDependency(Dependency* dependency); + + const char* Name() const; + + bool IsLastDependency(Dependency* dependency) const; + + DependencyFamily*& HashLink() { return fHashLink; } + +private: + DependencyFamily* fHashLink; + FamilyDependencyList fDependencies; +}; + + +inline void +DependencyFamily::AddDependency(Dependency* dependency) +{ + fDependencies.Add(dependency); + dependency->SetFamily(this); +} + + +inline void +DependencyFamily::RemoveDependency(Dependency* dependency) +{ + dependency->SetFamily(NULL); + fDependencies.Remove(dependency); +} + + +inline const char* +DependencyFamily::Name() const +{ + Dependency* head = fDependencies.Head(); + return head != NULL ? head->Name() : NULL; +} + + +inline bool +DependencyFamily::IsLastDependency(Dependency* dependency) const +{ + return fDependencies.Head() == dependency + && fDependencies.Tail() == dependency; +} + + +// #pragma mark - DependencyFamilyHashDefinition + + +struct DependencyFamilyHashDefinition { + typedef const char* KeyType; + typedef DependencyFamily ValueType; + + size_t HashKey(const char* key) const + { + return key != NULL ? hash_hash_string(key) : 0; + } + + size_t Hash(const DependencyFamily* value) const + { + return HashKey(value->Name()); + } + + bool Compare(const char* key, const DependencyFamily* value) const + { + return strcmp(value->Name(), key) == 0; + } + + DependencyFamily*& GetLink(DependencyFamily* value) const + { + return value->HashLink(); + } +}; + + +typedef BOpenHashTable + DependencyFamilyHashTable; + + +#endif // DEPENDENCY_FAMILY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index d9a68ab980..2a726cf622 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -30,6 +30,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageNodeAttribute.cpp PackageSymlink.cpp Resolvable.cpp + ResolvableFamily.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp UnpackingDirectory.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index 9ccc759164..d6ec920c0e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -60,7 +60,11 @@ public: int Open(); void Close(); - const PackageNodeList& Nodes() const { return fNodes; } + const PackageNodeList& Nodes() const { return fNodes; } + const ResolvableList& Resolvables() const + { return fResolvables; } + const DependencyList& Dependencies() const + { return fDependencies; } private: mutex fLock; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index aa4dcb8bae..3d05e7cad4 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -64,6 +64,14 @@ PackageFSRoot::Init() if (error != B_OK) RETURN_ERROR(error); + error = fResolvables.Init(); + if (error != B_OK) + RETURN_ERROR(error); + + error = fDependencies.Init(); + if (error != B_OK) + RETURN_ERROR(error); + return B_OK; } @@ -159,14 +167,24 @@ PackageFSRoot::UnregisterVolume(Volume* volume) status_t PackageFSRoot::AddPackage(Package* package) { - return fPackageLinksDirectory->AddPackage(package); + PackageFSRootWriteLocker writeLocker(this); + + status_t error = _AddPackage(package); + if (error != B_OK) { + _RemovePackage(package); + RETURN_ERROR(error); + } + + return B_OK; } void PackageFSRoot::RemovePackage(Package* package) { - fPackageLinksDirectory->RemovePackage(package); + PackageFSRootWriteLocker writeLocker(this); + + _RemovePackage(package); } @@ -209,6 +227,100 @@ PackageFSRoot::_RemoveVolume(Volume* volume) } +status_t +PackageFSRoot::_AddPackage(Package* package) +{ + ResolvableDependencyList dependenciesToUpdate; + + // register resolvables + for (ResolvableList::ConstIterator it + = package->Resolvables().GetIterator(); + Resolvable* resolvable = it.Next();) { + if (ResolvableFamily* family + = fResolvables.Lookup(resolvable->Name())) { + family->AddResolvable(resolvable, dependenciesToUpdate); + } else { + ResolvableFamily* family = new(std::nothrow) ResolvableFamily; + if (family == NULL) + return B_NO_MEMORY; + + family->AddResolvable(resolvable, dependenciesToUpdate); + fResolvables.Insert(family); + } + } + + // register dependencies + for (DependencyList::ConstIterator it + = package->Dependencies().GetIterator(); + Dependency* dependency = it.Next();) { + if (DependencyFamily* family + = fDependencies.Lookup(dependency->Name())) { + family->AddDependency(dependency); + } else { + DependencyFamily* family = new(std::nothrow) DependencyFamily; + if (family == NULL) + return B_NO_MEMORY; + + family->AddDependency(dependency); + fDependencies.Insert(family); + } + + dependenciesToUpdate.Add(dependency); + } + + return fPackageLinksDirectory->AddPackage(package); +} + + +void +PackageFSRoot::_RemovePackage(Package* package) +{ + fPackageLinksDirectory->RemovePackage(package); + + // unregister dependencies + for (DependencyList::ConstIterator it + = package->Dependencies().GetIterator(); + Dependency* dependency = it.Next();) { + if (DependencyFamily* family = dependency->Family()) { + if (family->IsLastDependency(dependency)) { + fDependencies.Remove(family); + family->RemoveDependency(dependency); + delete family; + } else + family->RemoveDependency(dependency); + } + } + + // unregister resolvables + ResolvableDependencyList dependenciesToUpdate; + + for (ResolvableList::ConstIterator it + = package->Resolvables().GetIterator(); + Resolvable* resolvable = it.Next();) { + if (ResolvableFamily* family = resolvable->Family()) { + if (family->IsLastResolvable(resolvable)) { + fResolvables.Remove(family); + family->RemoveResolvable(resolvable, dependenciesToUpdate); + delete family; + } else + family->RemoveResolvable(resolvable, dependenciesToUpdate); + } + } + + _ResolveDependencies(dependenciesToUpdate); +} + + +void +PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) +{ + if (dependencies.IsEmpty()) + return; + + // TODO:... +} + + /*static*/ status_t PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, PackageFSRoot*& _root) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h index 18d6618c49..acdaf9e128 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -13,6 +13,8 @@ #include +#include "DependencyFamily.h" +#include "ResolvableFamily.h" #include "Volume.h" @@ -58,6 +60,12 @@ private: status_t _AddVolume(Volume* volume); void _RemoveVolume(Volume* volume); + status_t _AddPackage(Package* package); + void _RemovePackage(Package* package); + + void _ResolveDependencies( + ResolvableDependencyList& dependencies); + static status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID, PackageFSRoot*& _root); static PackageFSRoot* _FindRootLocked(dev_t deviceID, ino_t nodeID); @@ -73,6 +81,8 @@ private: VolumeList fVolumes; Volume* fSystemVolume; PackageLinksDirectory* fPackageLinksDirectory; + ResolvableFamilyHashTable fResolvables; + DependencyFamilyHashTable fDependencies; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp index 7e00edb05f..d0cfc17d70 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp @@ -11,9 +11,10 @@ #include "Version.h" -Resolvable::Resolvable(Package* package) +Resolvable::Resolvable(::Package* package) : fPackage(package), + fFamily(NULL), fName(NULL), fVersion(NULL) { @@ -38,3 +39,34 @@ Resolvable::Init(const char* name, Version* version) return B_OK; } + + +void +Resolvable::AddDependency(Dependency* dependency) +{ + fDependencies.Add(dependency); + dependency->SetResolvable(this); +} + + +void +Resolvable::RemoveDependency(Dependency* dependency) +{ + fDependencies.Remove(dependency); + dependency->SetResolvable(NULL); +} + + +void +Resolvable::MoveDependencies(ResolvableDependencyList& dependencies) +{ + if (fDependencies.IsEmpty()) + return; + + for (ResolvableDependencyList::Iterator it = fDependencies.GetIterator(); + Dependency* dependency = it.Next();) { + dependency->SetResolvable(NULL); + } + + dependencies.MoveFrom(&fDependencies); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h index e73f6affc8..f68a4e3b80 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h @@ -10,29 +10,55 @@ #include +#include "Dependency.h" + class Package; +class ResolvableFamily; class Version; class Resolvable : public BReferenceable, public DoublyLinkedListLinkImpl { public: - Resolvable(Package* package); + Resolvable(::Package* package); virtual ~Resolvable(); status_t Init(const char* name, Version* version); // version is optional; object takes over // ownership (even in case of error) + ::Package* Package() const { return fPackage; } + + void SetFamily(ResolvableFamily* family) + { fFamily = family; } + ResolvableFamily* Family() const + { return fFamily; } + + const char* Name() const { return fName; } + + void AddDependency(Dependency* dependency); + void RemoveDependency(Dependency* dependency); + void MoveDependencies( + ResolvableDependencyList& dependencies); + private: - Package* fPackage; + ::Package* fPackage; + ResolvableFamily* fFamily; char* fName; Version* fVersion; + ResolvableDependencyList fDependencies; + +public: // conceptually package private + DoublyLinkedListLink fFamilyListLink; }; typedef DoublyLinkedList ResolvableList; +typedef DoublyLinkedList > FamilyResolvableList; + #endif // RESOLVABLE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp new file mode 100644 index 0000000000..ab9060f204 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ResolvableFamily.h" + +#include "Package.h" +#include "Volume.h" + + +void +ResolvableFamily::AddResolvable(Resolvable* resolvable, + ResolvableDependencyList& dependenciesToUpdate) +{ + // Find the insertion point in the list. We sort by mount type -- the more + // specific the higher the priority. + MountType mountType + = resolvable->Package()->Domain()->Volume()->MountType(); + Resolvable* otherResolvable = NULL; + for (FamilyResolvableList::Iterator it = fResolvables.GetIterator(); + (otherResolvable = it.Next()) != NULL;) { + if (otherResolvable->Package()->Domain()->Volume()->MountType() + <= mountType) { + break; + } + } + + fResolvables.InsertBefore(otherResolvable, resolvable); + resolvable->SetFamily(this); + + // all dependencies after the inserted resolvable potentially need to be + // updated + while ((resolvable = fResolvables.GetNext(resolvable)) != NULL) + resolvable->MoveDependencies(dependenciesToUpdate); +} + + +void +ResolvableFamily::RemoveResolvable(Resolvable* resolvable, + ResolvableDependencyList& dependenciesToUpdate) +{ + resolvable->SetFamily(NULL); + fResolvables.Remove(resolvable); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h new file mode 100644 index 0000000000..c63c3322f8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef RESOLVABLE_FAMILY_H +#define RESOLVABLE_FAMILY_H + + +#include +#include + +#include "Resolvable.h" + + +class ResolvableFamily { +public: + void AddResolvable(Resolvable* resolvable, + ResolvableDependencyList& + dependenciesToUpdate); + void RemoveResolvable(Resolvable* resolvable, + ResolvableDependencyList& + dependenciesToUpdate); + + const char* Name() const; + + bool IsLastResolvable(Resolvable* resolvable) const; + + ResolvableFamily*& HashLink() { return fHashLink; } + +private: + ResolvableFamily* fHashLink; + FamilyResolvableList fResolvables; +}; + + +inline const char* +ResolvableFamily::Name() const +{ + Resolvable* head = fResolvables.Head(); + return head != NULL ? head->Name() : NULL; +} + + +inline bool +ResolvableFamily::IsLastResolvable(Resolvable* resolvable) const +{ + return fResolvables.Head() == resolvable + && fResolvables.Tail() == resolvable; +} + + +// #pragma mark - ResolvableFamilyHashDefinition + + +struct ResolvableFamilyHashDefinition { + typedef const char* KeyType; + typedef ResolvableFamily ValueType; + + size_t HashKey(const char* key) const + { + return key != NULL ? hash_hash_string(key) : 0; + } + + size_t Hash(const ResolvableFamily* value) const + { + return HashKey(value->Name()); + } + + bool Compare(const char* key, const ResolvableFamily* value) const + { + return strcmp(value->Name(), key) == 0; + } + + ResolvableFamily*& GetLink(ResolvableFamily* value) const + { + return value->HashLink(); + } +}; + + +typedef BOpenHashTable + ResolvableFamilyHashTable; + + +#endif // RESOLVABLE_FAMILY_H