packagefs: Share string instances globally

Introduce a class String which refers to shared private data that is
registered in a global hash table (in class StringPool) and use the
class consequently. This eliminates duplicate allocations for the same
string and also speeds up tests for equality. There's quite a bit
overhead for the management structures (apparently even more than for
the string data itself), but due to almost all strings being used
multiple times this still almost halves the memory usage for string
data.
This commit is contained in:
Ingo Weinhold 2013-05-11 23:31:36 +02:00
parent 1848fdc329
commit d07c930c1e
55 changed files with 980 additions and 302 deletions

View File

@ -53,6 +53,9 @@ HAIKU_PACKAGE_FS_SOURCES =
Resolvable.cpp
ResolvableFamily.cpp
SizeIndex.cpp
String.cpp
StringConstants.cpp
StringPool.cpp
UnpackingAttributeCookie.cpp
UnpackingAttributeDirectoryCookie.cpp
UnpackingDirectory.cpp

View File

@ -8,6 +8,8 @@
#include <SupportDefs.h>
#include "String.h"
class AttributeIndex;
class AttributeIndexTreeValue;
@ -28,12 +30,12 @@ public:
AttributeIndexTreeValue* Cookie() const
{ return fCookie; }
const char* IndexName() const
const String& IndexName() const
{ return fIndexName; }
private:
AttributeIndex* fIndex;
const char* fIndexName;
const String& fIndexName;
uint32 fIndexType;
AttributeIndexTreeValue* fCookie;
};

View File

@ -18,7 +18,7 @@
Index::Index()
:
fVolume(NULL),
fName(NULL),
fName(),
fType(0),
fKeyLength(0),
fFixedKeyLength(true)
@ -28,7 +28,6 @@ Index::Index()
Index::~Index()
{
free(fName);
}
@ -36,8 +35,7 @@ status_t
Index::Init(Volume* volume, const char* name, uint32 type, bool fixedKeyLength,
size_t keyLength)
{
fName = strdup(name);
if (fName == NULL)
if (!fName.SetTo(name))
return B_NO_MEMORY;
fVolume = volume;

View File

@ -13,6 +13,9 @@
#include <util/khash.h>
#include <util/OpenHashTable.h>
#include "String.h"
#include "StringKey.h"
class AbstractIndexIterator;
class IndexIterator;
@ -34,7 +37,7 @@ public:
Volume* GetVolume() const { return fVolume; }
const char* Name() const { return fName; }
const String& Name() const { return fName; }
uint32 Type() const { return fType; }
bool HasFixedKeyLength() const
{ return fFixedKeyLength; }
@ -64,7 +67,7 @@ protected:
protected:
Index* fHashLink;
Volume* fVolume;
char* fName;
String fName;
uint32 fType;
size_t fKeyLength;
bool fFixedKeyLength;
@ -98,22 +101,22 @@ private:
struct IndexHashDefinition {
typedef const char* KeyType;
typedef StringKey KeyType;
typedef Index ValueType;
size_t HashKey(const char* key) const
size_t HashKey(const StringKey& key) const
{
return key != NULL ? hash_hash_string(key) : 0;
return key.Hash();
}
size_t Hash(const Index* value) const
{
return HashKey(value->Name());
return value->Name().Hash();
}
bool Compare(const char* key, const Index* value) const
bool Compare(const StringKey& key, const Index* value) const
{
return strcmp(value->Name(), key) == 0;
return key == value->Name();
}
Index*& GetLink(Index* value) const

View File

@ -84,7 +84,7 @@ struct Query::QueryPolicy {
static status_t IndexSetTo(Index& index, const char* attribute)
{
index.index = index.query->fVolume->FindIndex(attribute);
index.index = index.query->fVolume->FindIndex(StringKey(attribute));
return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
}
@ -181,7 +181,8 @@ struct Query::QueryPolicy {
{
// TODO: Creating a cookie is quite a bit of overhead.
AttributeCookie* cookie;
status_t error = node->OpenAttribute(attribute, O_RDONLY, cookie);
status_t error = node->OpenAttribute(StringKey(attribute), O_RDONLY,
cookie);
if (error != B_OK)
return error;

View File

@ -24,6 +24,8 @@
#include "GlobalFactory.h"
#include "Query.h"
#include "PackageFSRoot.h"
#include "StringConstants.h"
#include "StringPool.h"
#include "Utils.h"
#include "Volume.h"
@ -181,7 +183,8 @@ packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
// resolve normal entries -- look up the node
NodeReadLocker dirLocker(dir);
Node* node = dynamic_cast<Directory*>(dir)->FindChild(entryName);
String entryNameString;
Node* node = dynamic_cast<Directory*>(dir)->FindChild(StringKey(entryName));
if (node == NULL)
return B_ENTRY_NOT_FOUND;
BReference<Node> nodeReference(node);
@ -792,7 +795,7 @@ packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
return error;
AttributeCookie* cookie;
error = node->OpenAttribute(name, openMode, cookie);
error = node->OpenAttribute(StringKey(name), openMode, cookie);
if (error != B_OK)
return error;
@ -976,7 +979,7 @@ packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
Index* index = volume->FindIndex(name);
Index* index = volume->FindIndex(StringKey(name));
if (index == NULL)
return B_ENTRY_NOT_FOUND;
@ -1093,9 +1096,25 @@ packagefs_std_ops(int32 op, ...)
init_debugging();
PRINT("package_std_ops(): B_MODULE_INIT\n");
status_t error = GlobalFactory::CreateDefault();
status_t error = StringPool::Init();
if (error != B_OK) {
ERROR("Failed to init StringPool\n");
exit_debugging();
return error;
}
if (!StringConstants::Init()) {
ERROR("Failed to init string constants\n");
StringPool::Cleanup();
exit_debugging();
return error;
}
error = GlobalFactory::CreateDefault();
if (error != B_OK) {
ERROR("Failed to init GlobalFactory\n");
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();
return error;
}
@ -1104,6 +1123,8 @@ packagefs_std_ops(int32 op, ...)
if (error != B_OK) {
ERROR("Failed to init PackageFSRoot\n");
GlobalFactory::DeleteDefault();
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();
return error;
}
@ -1116,6 +1137,8 @@ packagefs_std_ops(int32 op, ...)
PRINT("package_std_ops(): B_MODULE_UNINIT\n");
PackageFSRoot::GlobalUninit();
GlobalFactory::DeleteDefault();
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();
return B_OK;
}

View File

@ -16,11 +16,7 @@
#include "AttributeCookie.h"
#include "DebugSupport.h"
#include "Package.h"
static const char* const kAttributeNames[AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT] = {
"SYS:PACKAGE"
};
#include "StringConstants.h"
class AutoPackageAttributeCookie : public AttributeCookie {
@ -81,11 +77,11 @@ private:
/*static*/ bool
AutoPackageAttributes::AttributeForName(const char* name,
AutoPackageAttributes::AttributeForName(const StringKey& name,
AutoPackageAttribute& _attribute)
{
for (int i = 0; i < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT; i++) {
if (strcmp(name, kAttributeNames[i]) == 0) {
if (name == StringConstants::Get().kAutoPackageAttributeNames[i]) {
_attribute = (AutoPackageAttribute)i;
return true;
}
@ -95,12 +91,11 @@ AutoPackageAttributes::AttributeForName(const char* name,
}
/*static*/ const char*
/*static*/ const String&
AutoPackageAttributes::NameForAttribute(AutoPackageAttribute attribute)
{
if (attribute >= 0 && attribute < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT)
return kAttributeNames[attribute];
return NULL;
ASSERT(attribute >= 0 && attribute < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT);
return StringConstants::Get().kAutoPackageAttributeNames[attribute];
}
@ -124,7 +119,7 @@ AutoPackageAttributes::GetAttributeValue(const Package* package,
/*static*/ status_t
AutoPackageAttributes::OpenCookie(Package* package, const char* name,
AutoPackageAttributes::OpenCookie(Package* package, const StringKey& name,
int openMode, AttributeCookie*& _cookie)
{
if (package == NULL)

View File

@ -8,6 +8,8 @@
#include <SupportDefs.h>
#include "StringKey.h"
class AttributeCookie;
class Package;
@ -22,16 +24,17 @@ enum AutoPackageAttribute {
struct AutoPackageAttributes {
static bool AttributeForName(const char* name,
static bool AttributeForName(const StringKey& name,
AutoPackageAttribute& _attribute);
static const char* NameForAttribute(
static const String& NameForAttribute(
AutoPackageAttribute attribute);
static const void* GetAttributeValue(const Package* package,
AutoPackageAttribute attribute,
off_t& _size, uint32& _type);
static status_t OpenCookie(Package* package, const char* name,
int openMode, AttributeCookie*& _cookie);
static status_t OpenCookie(Package* package,
const StringKey& name, int openMode,
AttributeCookie*& _cookie);
};

View File

@ -31,9 +31,9 @@ Directory::~Directory()
status_t
Directory::Init(Directory* parent, const char* name, uint32 flags)
Directory::Init(Directory* parent, const String& name)
{
status_t error = Node::Init(parent, name, flags);
status_t error = Node::Init(parent, name);
if (error != B_OK)
return error;
@ -104,7 +104,7 @@ Directory::RemoveChild(Node* node)
Node*
Directory::FindChild(const char* name)
Directory::FindChild(const StringKey& name)
{
return fChildTable.Lookup(name);
}

View File

@ -27,8 +27,7 @@ public:
Directory(ino_t id);
virtual ~Directory();
virtual status_t Init(Directory* parent, const char* name,
uint32 flags);
virtual status_t Init(Directory* parent, const String& name);
virtual mode_t Mode() const;
virtual off_t FileSize() const;
@ -41,7 +40,7 @@ public:
void AddChild(Node* node);
void RemoveChild(Node* node);
Node* FindChild(const char* name);
Node* FindChild(const StringKey& name);
inline Node* FirstChild() const;
inline Node* NextChild(Node* node) const;

View File

@ -17,7 +17,7 @@ Node::Node(ino_t id)
:
fID(id),
fParent(NULL),
fName(NULL),
fName(),
fFlags(0)
{
rw_lock_init(&fLock, "packagefs node");
@ -26,29 +26,16 @@ Node::Node(ino_t id)
Node::~Node()
{
if ((fFlags & NODE_FLAG_OWNS_NAME) != 0)
free(fName);
rw_lock_destroy(&fLock);
}
status_t
Node::Init(Directory* parent, const char* name, uint32 flags)
Node::Init(Directory* parent, const String& name)
{
fParent = parent;
fFlags = flags;
if ((flags & NODE_FLAG_CONST_NAME) != 0
|| (flags & NODE_FLAG_KEEP_NAME) != 0) {
fName = const_cast<char*>(name);
} else {
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
fFlags |= NODE_FLAG_OWNS_NAME;
}
fName = name;
fFlags = 0;
return B_OK;
}
@ -110,7 +97,8 @@ Node::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
status_t
Node::OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie)
Node::OpenAttribute(const StringKey& name, int openMode,
AttributeCookie*& _cookie)
{
return B_ENTRY_NOT_FOUND;
}
@ -124,7 +112,7 @@ Node::IndexAttribute(AttributeIndexer* indexer)
void*
Node::IndexCookieForAttribute(const char* name) const
Node::IndexCookieForAttribute(const StringKey& name) const
{
return NULL;
}

View File

@ -16,6 +16,9 @@
#include <util/khash.h>
#include <util/OpenHashTable.h>
#include "String.h"
#include "StringKey.h"
class AttributeCookie;
class AttributeDirectoryCookie;
@ -26,14 +29,7 @@ class PackageNode;
// node flags
enum {
NODE_FLAG_KEEP_NAME = 0x01,
// Init(): Take over ownership of the given name (i.e. free in
// destructor).
NODE_FLAG_CONST_NAME = 0x02,
// Init(): The given name is a constant that won't go away during the
// lifetime of the object. No need to copy.
NODE_FLAG_OWNS_NAME = NODE_FLAG_KEEP_NAME,
NODE_FLAG_KNOWN_TO_VFS = 0x04,
NODE_FLAG_KNOWN_TO_VFS = 0x01
// internal flag
};
@ -50,17 +46,14 @@ public:
ino_t ID() const { return fID; }
Directory* Parent() const { return fParent; }
const char* Name() const { return fName; }
const String& Name() const { return fName; }
Node*& NameHashTableNext()
{ return fNameHashTableNext; }
Node*& IDHashTableNext()
{ return fIDHashTableNext; }
virtual status_t Init(Directory* parent, const char* name,
uint32 flags);
// If specified to keep the name, it does
// so also on error.
virtual status_t Init(Directory* parent, const String& name);
virtual status_t VFSInit(dev_t deviceID);
// base class version must be called on
@ -87,17 +80,18 @@ public:
virtual status_t OpenAttributeDirectory(
AttributeDirectoryCookie*& _cookie);
virtual status_t OpenAttribute(const char* name, int openMode,
AttributeCookie*& _cookie);
virtual status_t OpenAttribute(const StringKey& name,
int openMode, AttributeCookie*& _cookie);
virtual status_t IndexAttribute(AttributeIndexer* indexer);
virtual void* IndexCookieForAttribute(const char* name) const;
virtual void* IndexCookieForAttribute(const StringKey& name)
const;
protected:
rw_lock fLock;
ino_t fID;
Directory* fParent;
char* fName;
String fName;
Node* fNameHashTableNext;
Node* fIDHashTableNext;
uint32 fFlags;
@ -143,22 +137,22 @@ Node::IsKnownToVFS() const
struct NodeNameHashDefinition {
typedef const char* KeyType;
typedef StringKey KeyType;
typedef Node ValueType;
size_t HashKey(const char* key) const
size_t HashKey(const StringKey& key) const
{
return hash_hash_string(key);
return key.Hash();
}
size_t Hash(const Node* value) const
{
return HashKey(value->Name());
return value->Name().Hash();
}
bool Compare(const char* key, const Node* value) const
bool Compare(const StringKey& key, const Node* value) const
{
return strcmp(value->Name(), key) == 0;
return key == value->Name();
}
Node*& GetLink(Node* value) const

View File

@ -36,7 +36,7 @@ OldUnpackingNodeAttributes::FileSize() const
void*
OldUnpackingNodeAttributes::IndexCookieForAttribute(const char* name) const
OldUnpackingNodeAttributes::IndexCookieForAttribute(const StringKey& name) const
{
return fPackageNode != NULL
? fPackageNode->IndexCookieForAttribute(name) : NULL;

View File

@ -19,7 +19,8 @@ public:
virtual timespec ModifiedTime() const;
virtual off_t FileSize() const;
virtual void* IndexCookieForAttribute(const char* name) const;
virtual void* IndexCookieForAttribute(const StringKey& name)
const;
private:
PackageNode* fPackageNode;

View File

@ -80,7 +80,7 @@ UnpackingAttributeCookie::~UnpackingAttributeCookie()
/*static*/ status_t
UnpackingAttributeCookie::Open(PackageNode* packageNode, const char* name,
UnpackingAttributeCookie::Open(PackageNode* packageNode, const StringKey& name,
int openMode, AttributeCookie*& _cookie)
{
if (packageNode == NULL)

View File

@ -7,6 +7,7 @@
#include "AttributeCookie.h"
#include "StringKey.h"
class AttributeIndexer;
@ -23,8 +24,9 @@ public:
int openMode);
virtual ~UnpackingAttributeCookie();
static status_t Open(PackageNode* packageNode, const char* name,
int openMode, AttributeCookie*& _cookie);
static status_t Open(PackageNode* packageNode,
const StringKey& name, int openMode,
AttributeCookie*& _cookie);
virtual status_t ReadAttribute(off_t offset, void* buffer,
size_t* bufferSize);

View File

@ -75,12 +75,10 @@ UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID,
}
// get the attribute name
const char* name;
if (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT) {
name = AutoPackageAttributes::NameForAttribute(
(AutoPackageAttribute)fState);
} else
name = fAttribute->Name();
const String& name = fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT
? AutoPackageAttributes::NameForAttribute(
(AutoPackageAttribute)fState)
: fAttribute->Name();
// fill in the entry name -- checks whether the entry fits into the
// buffer

View File

@ -170,7 +170,7 @@ UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
status_t
UnpackingDirectory::OpenAttribute(const char* name, int openMode,
UnpackingDirectory::OpenAttribute(const StringKey& name, int openMode,
AttributeCookie*& _cookie)
{
return UnpackingAttributeCookie::Open(fPackageDirectories.Head(), name,
@ -187,7 +187,7 @@ UnpackingDirectory::IndexAttribute(AttributeIndexer* indexer)
void*
UnpackingDirectory::IndexCookieForAttribute(const char* name) const
UnpackingDirectory::IndexCookieForAttribute(const StringKey& name) const
{
if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
return packageDirectory->IndexCookieForAttribute(name);

View File

@ -36,11 +36,12 @@ public:
virtual status_t OpenAttributeDirectory(
AttributeDirectoryCookie*& _cookie);
virtual status_t OpenAttribute(const char* name, int openMode,
AttributeCookie*& _cookie);
virtual status_t OpenAttribute(const StringKey& name,
int openMode, AttributeCookie*& _cookie);
virtual status_t IndexAttribute(AttributeIndexer* indexer);
virtual void* IndexCookieForAttribute(const char* name) const;
virtual void* IndexCookieForAttribute(const StringKey& name)
const;
private:
PackageDirectoryList fPackageDirectories;

View File

@ -216,7 +216,7 @@ UnpackingLeafNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode)
if (clone == NULL)
return B_NO_MEMORY;
status_t error = clone->Init(Parent(), Name(), 0);
status_t error = clone->Init(Parent(), Name());
if (error != B_OK) {
delete clone;
return error;
@ -260,8 +260,8 @@ UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
if (packageNode == NULL)
return B_BAD_VALUE;
const char* linkPath = packageNode->SymlinkPath();
if (linkPath == NULL) {
const String& linkPath = packageNode->SymlinkPath();
if (linkPath[0] == '\0') {
*bufferSize = 0;
return B_OK;
}
@ -283,7 +283,7 @@ UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
status_t
UnpackingLeafNode::OpenAttribute(const char* name, int openMode,
UnpackingLeafNode::OpenAttribute(const StringKey& name, int openMode,
AttributeCookie*& _cookie)
{
return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode,
@ -300,7 +300,7 @@ UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
void*
UnpackingLeafNode::IndexCookieForAttribute(const char* name) const
UnpackingLeafNode::IndexCookieForAttribute(const StringKey& name) const
{
if (PackageLeafNode* packageNode = _ActivePackageNode())
return packageNode->IndexCookieForAttribute(name);

View File

@ -48,11 +48,12 @@ public:
virtual status_t OpenAttributeDirectory(
AttributeDirectoryCookie*& _cookie);
virtual status_t OpenAttribute(const char* name, int openMode,
AttributeCookie*& _cookie);
virtual status_t OpenAttribute(const StringKey& name,
int openMode, AttributeCookie*& _cookie);
virtual status_t IndexAttribute(AttributeIndexer* indexer);
virtual void* IndexCookieForAttribute(const char* name) const;
virtual void* IndexCookieForAttribute(const StringKey& name)
const;
private:
inline PackageLeafNode* _ActivePackageNode() const;

View File

@ -88,8 +88,6 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
RETURN_ERROR(B_BAD_DATA);
}
status_t error;
// get the file mode -- filter out write permissions
mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
@ -100,17 +98,16 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data());
} else if (S_ISLNK(mode)) {
// symlink
String path;
if (!path.SetTo(entry->SymlinkPath()))
RETURN_ERROR(B_NO_MEMORY);
PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
fPackage, mode);
if (symlink == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = symlink->SetSymlinkPath(entry->SymlinkPath());
if (error != B_OK) {
delete symlink;
return error;
}
symlink->SetSymlinkPath(path);
node = symlink;
} else if (S_ISDIR(mode)) {
// directory
@ -122,7 +119,11 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
RETURN_ERROR(B_NO_MEMORY);
BReference<PackageNode> nodeReference(node, true);
error = node->Init(parentDir, entry->Name());
String entryName;
if (!entryName.SetTo(entry->Name()))
RETURN_ERROR(B_NO_MEMORY);
status_t error = node->Init(parentDir, entryName);
if (error != B_OK)
RETURN_ERROR(error);
@ -147,17 +148,16 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
PackageNode* node = (PackageNode*)entry->UserToken();
String name;
if (!name.SetTo(attribute->Name()))
RETURN_ERROR(B_NO_MEMORY);
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(attribute->Type(), attribute->Data());
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
status_t error = nodeAttribute->Init(attribute->Name());
if (error != B_OK) {
delete nodeAttribute;
RETURN_ERROR(error);
}
nodeAttribute->Init(name);
node->AddAttribute(nodeAttribute);
return B_OK;
@ -173,10 +173,22 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
{
switch (value.attributeID) {
case B_PACKAGE_INFO_NAME:
return fPackage->SetName(value.string);
{
String name;
if (!name.SetTo(value.string))
return B_NO_MEMORY;
fPackage->SetName(name);
return B_OK;
}
case B_PACKAGE_INFO_INSTALL_PATH:
return fPackage->SetInstallPath(value.string);
{
String path;
if (!path.SetTo(value.string))
return B_NO_MEMORY;
fPackage->SetInstallPath(path);
return B_OK;
}
case B_PACKAGE_INFO_VERSION:
{
@ -303,9 +315,9 @@ private:
Package::Package(::Volume* volume, dev_t deviceID, ino_t nodeID)
:
fVolume(volume),
fFileName(NULL),
fName(NULL),
fInstallPath(NULL),
fFileName(),
fName(),
fInstallPath(),
fVersion(NULL),
fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
fLinkDirectory(NULL),
@ -329,9 +341,6 @@ Package::~Package()
while (Dependency* dependency = fDependencies.RemoveHead())
delete dependency;
free(fFileName);
free(fName);
free(fInstallPath);
delete fVersion;
mutex_destroy(&fLock);
@ -341,8 +350,7 @@ Package::~Package()
status_t
Package::Init(const char* fileName)
{
fFileName = strdup(fileName);
if (fFileName == NULL)
if (!fFileName.SetTo(fileName))
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
@ -379,31 +387,17 @@ Package::Load()
}
status_t
Package::SetName(const char* name)
void
Package::SetName(const String& name)
{
if (fName != NULL)
free(fName);
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
fName = name;
}
status_t
Package::SetInstallPath(const char* installPath)
void
Package::SetInstallPath(const String& installPath)
{
if (fInstallPath != NULL)
free(fInstallPath);
fInstallPath = strdup(installPath);
if (fInstallPath == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
fInstallPath = installPath;
}
@ -463,14 +457,14 @@ Package::Open()
// open the file
fFD = openat(fVolume->PackagesDirectoryFD(), fFileName, O_RDONLY);
if (fFD < 0) {
ERROR("Failed to open package file \"%s\"\n", fFileName);
ERROR("Failed to open package file \"%s\"\n", fFileName.Data());
return errno;
}
// stat it to verify that it's still the same file
struct stat st;
if (fstat(fFD, &st) < 0) {
ERROR("Failed to stat package file \"%s\"\n", fFileName);
ERROR("Failed to stat package file \"%s\"\n", fFileName.Data());
close(fFD);
fFD = -1;
return errno;

View File

@ -19,6 +19,7 @@
#include "Dependency.h"
#include "PackageNode.h"
#include "Resolvable.h"
#include "String.h"
using BPackageKit::BPackageArchitecture;
@ -40,18 +41,18 @@ public:
status_t Load();
::Volume* Volume() const { return fVolume; }
const char* FileName() const { return fFileName; }
const String& FileName() const { return fFileName; }
status_t SetName(const char* name);
const char* Name() const { return fName; }
void SetName(const String& name);
const String& Name() const { return fName; }
dev_t DeviceID() const
{ return fDeviceID; }
ino_t NodeID() const
{ return fNodeID; }
status_t SetInstallPath(const char* installPath);
const char* InstallPath() const { return fInstallPath; }
void SetInstallPath(const String& installPath);
const String& InstallPath() const { return fInstallPath; }
void SetVersion(::Version* version);
// takes over object ownership
@ -94,9 +95,9 @@ private:
private:
mutex fLock;
::Volume* fVolume;
char* fFileName;
char* fName;
char* fInstallPath;
String fFileName;
String fName;
String fInstallPath;
::Version* fVersion;
BPackageArchitecture fArchitecture;
PackageLinkDirectory* fLinkDirectory;
@ -145,7 +146,7 @@ struct PackageFileNameHashDefinition {
size_t Hash(const Package* value) const
{
return HashKey(value->FileName());
return value->FileName().Hash();
}
bool Compare(const char* key, const Package* value) const

View File

@ -19,10 +19,10 @@ PackageLeafNode::~PackageLeafNode()
}
const char*
String
PackageLeafNode::SymlinkPath() const
{
return NULL;
return String();
}

View File

@ -19,7 +19,7 @@ public:
PackageLeafNode(Package* package, mode_t mode);
virtual ~PackageLeafNode();
virtual const char* SymlinkPath() const;
virtual String SymlinkPath() const;
virtual status_t Read(off_t offset, void* buffer,
size_t* bufferSize);

View File

@ -17,7 +17,7 @@ PackageNode::PackageNode(Package* package, mode_t mode)
:
fPackage(package),
fParent(NULL),
fName(NULL),
fName(),
fMode(mode),
fUserID(0),
fGroupID(0)
@ -29,19 +29,14 @@ PackageNode::~PackageNode()
{
while (PackageNodeAttribute* attribute = fAttributes.RemoveHead())
delete attribute;
free(fName);
}
status_t
PackageNode::Init(PackageDirectory* parent, const char* name)
PackageNode::Init(PackageDirectory* parent, const String& name)
{
fParent = parent;
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
fName = name;
return B_OK;
}
@ -83,11 +78,11 @@ PackageNode::RemoveAttribute(PackageNodeAttribute* attribute)
PackageNodeAttribute*
PackageNode::FindAttribute(const char* name) const
PackageNode::FindAttribute(const StringKey& name) const
{
for (PackageNodeAttributeList::ConstIterator it = fAttributes.GetIterator();
PackageNodeAttribute* attribute = it.Next();) {
if (strcmp(attribute->Name(), name) == 0)
if (name == attribute->Name())
return attribute;
}

View File

@ -14,6 +14,7 @@
#include "IndexedAttributeOwner.h"
#include "PackageNodeAttribute.h"
#include "StringKey.h"
class AttributeIndexer;
@ -34,10 +35,10 @@ public:
// must otherwise make sure the package
// still exists.
PackageDirectory* Parent() const { return fParent; }
const char* Name() const { return fName; }
const String& Name() const { return fName; }
virtual status_t Init(PackageDirectory* parent,
const char* name);
const String& name);
virtual status_t VFSInit(dev_t deviceID, ino_t nodeID);
virtual void VFSUninit();
@ -65,11 +66,12 @@ public:
const PackageNodeAttributeList& Attributes() const
{ return fAttributes; }
PackageNodeAttribute* FindAttribute(const char* name) const;
PackageNodeAttribute* FindAttribute(const StringKey& name) const;
virtual void UnsetIndexCookie(void* attributeCookie);
inline void* IndexCookieForAttribute(const char* name) const;
inline void* IndexCookieForAttribute(const StringKey& name)
const;
protected:
void NonVirtualVFSUninit()
@ -80,7 +82,7 @@ protected:
protected:
Package* fPackage;
PackageDirectory* fParent;
char* fName;
String fName;
mode_t fMode;
uid_t fUserID;
gid_t fGroupID;
@ -90,7 +92,7 @@ protected:
void*
PackageNode::IndexCookieForAttribute(const char* name) const
PackageNode::IndexCookieForAttribute(const StringKey& name) const
{
PackageNodeAttribute* attribute = FindAttribute(name);
return attribute != NULL ? attribute->IndexCookie() : NULL;

View File

@ -14,7 +14,7 @@ PackageNodeAttribute::PackageNodeAttribute(uint32 type,
const BPackageData& data)
:
fData(data),
fName(NULL),
fName(),
fIndexCookie(NULL),
fType(type)
{
@ -23,13 +23,11 @@ PackageNodeAttribute::PackageNodeAttribute(uint32 type,
PackageNodeAttribute::~PackageNodeAttribute()
{
free(fName);
}
status_t
PackageNodeAttribute::Init(const char* name)
void
PackageNodeAttribute::Init(const String& name)
{
fName = strdup(name);
return fName != NULL ? B_OK : B_NO_MEMORY;
fName = name;
}

View File

@ -10,6 +10,8 @@
#include <package/hpkg/PackageData.h>
#include "String.h"
using BPackageKit::BHPKG::BPackageData;
@ -23,11 +25,11 @@ public:
const BPackageData& data);
~PackageNodeAttribute();
const char* Name() const { return fName; }
const String& Name() const { return fName; }
uint32 Type() const { return fType; }
const BPackageData& Data() const { return fData; }
status_t Init(const char* name);
void Init(const String& name);
void SetIndexCookie(void* cookie)
{ fIndexCookie = cookie; }
@ -36,7 +38,7 @@ public:
protected:
BPackageData fData;
char* fName;
String fName;
void* fIndexCookie;
uint32 fType;
};

View File

@ -13,29 +13,24 @@
PackageSymlink::PackageSymlink(Package* package, mode_t mode)
:
PackageLeafNode(package, mode),
fSymlinkPath(NULL)
fSymlinkPath()
{
}
PackageSymlink::~PackageSymlink()
{
free(fSymlinkPath);
}
status_t
PackageSymlink::SetSymlinkPath(const char* path)
void
PackageSymlink::SetSymlinkPath(const String& path)
{
if (path == NULL)
return B_OK;
fSymlinkPath = strdup(path);
return fSymlinkPath != NULL ? B_OK : B_NO_MEMORY;
fSymlinkPath = path;
}
const char*
String
PackageSymlink::SymlinkPath() const
{
return fSymlinkPath;

View File

@ -14,12 +14,12 @@ public:
PackageSymlink(Package* package, mode_t mode);
virtual ~PackageSymlink();
status_t SetSymlinkPath(const char* path);
void SetSymlinkPath(const String& path);
virtual const char* SymlinkPath() const;
virtual String SymlinkPath() const;
private:
char* fSymlinkPath;
String fSymlinkPath;
};

View File

@ -14,15 +14,12 @@
#include "DebugSupport.h"
#include "PackageLinksListener.h"
#include "StringConstants.h"
#include "Utils.h"
#include "Version.h"
#include "Volume.h"
static const char* const kSelfLinkName = ".self";
static const char* const kSettingsLinkName = ".settings";
PackageLinkDirectory::PackageLinkDirectory()
:
Directory(0),
@ -63,6 +60,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package)
char* name = (char*)malloc(size);
if (name == NULL)
return B_NO_MEMORY;
MemoryDeleter nameDeleter(name);
memcpy(name, package->Name(), nameLength + 1);
if (version != NULL) {
@ -70,8 +68,12 @@ PackageLinkDirectory::Init(Directory* parent, Package* package)
version->ToString(name + nameLength + 1, size - nameLength - 1);
}
String nameString;
if (!nameString.SetTo(name))
return B_NO_MEMORY;
// init the directory/node
status_t error = Init(parent, name, NODE_FLAG_KEEP_NAME);
status_t error = Init(parent, nameString);
if (error != B_OK)
RETURN_ERROR(error);
@ -83,9 +85,9 @@ PackageLinkDirectory::Init(Directory* parent, Package* package)
status_t
PackageLinkDirectory::Init(Directory* parent, const char* name, uint32 flags)
PackageLinkDirectory::Init(Directory* parent, const String& name)
{
return Directory::Init(parent, name, flags);
return Directory::Init(parent, name);
}
@ -176,12 +178,13 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener)
// create/update self and settings link
status_t error = _CreateOrUpdateLink(fSelfLink, package,
Link::TYPE_INSTALLATION_LOCATION, kSelfLinkName, listener);
Link::TYPE_INSTALLATION_LOCATION, StringConstants::Get().kSelfLinkName,
listener);
if (error != B_OK)
RETURN_ERROR(error);
error = _CreateOrUpdateLink(fSettingsLink, package, Link::TYPE_SETTINGS,
kSettingsLinkName, listener);
StringConstants::Get().kSettingsLinkName, listener);
if (error != B_OK)
RETURN_ERROR(error);
@ -219,7 +222,7 @@ PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener)
if (link == NULL)
return B_NO_MEMORY;
status_t error = link->Init(this, dependency->Name(), 0);
status_t error = link->Init(this, dependency->Name());
if (error != B_OK) {
delete link;
RETURN_ERROR(error);
@ -256,14 +259,14 @@ PackageLinkDirectory::_RemoveLink(Link* link, PackageLinksListener* listener)
status_t
PackageLinkDirectory::_CreateOrUpdateLink(Link*& link, Package* package,
Link::Type type, const char* name, PackageLinksListener* listener)
Link::Type type, const String& name, PackageLinksListener* listener)
{
if (link == NULL) {
link = new(std::nothrow) Link(package, type);
if (link == NULL)
return B_NO_MEMORY;
status_t error = link->Init(this, name, NODE_FLAG_CONST_NAME);
status_t error = link->Init(this, name);
if (error != B_OK)
RETURN_ERROR(error);

View File

@ -20,8 +20,7 @@ public:
virtual ~PackageLinkDirectory();
status_t Init(Directory* parent, Package* package);
virtual status_t Init(Directory* parent, const char* name,
uint32 flags);
virtual status_t Init(Directory* parent, const String& name);
virtual timespec ModifiedTime() const;
@ -60,7 +59,7 @@ private:
status_t _CreateOrUpdateLink(Link*& link,
Package* package, Link::Type type,
const char* name,
const String& name,
PackageLinksListener* listener);
void _RemoveLink(Link* link,
PackageLinksListener* listener);

View File

@ -98,7 +98,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
if (package != NULL) {
fLinkPath = package->InstallPath();
if (fLinkPath != NULL) {
if (fLinkPath[0] != '\0') {
if (fType == TYPE_SETTINGS)
fLinkPath = ".self/settings";
} else {

View File

@ -17,7 +17,7 @@ Dependency::Dependency(::Package* package)
fPackage(package),
fFamily(NULL),
fResolvable(NULL),
fName(NULL),
fName(),
fVersion(NULL),
fVersionOperator(B_PACKAGE_RESOLVABLE_OP_EQUAL)
{
@ -26,7 +26,6 @@ Dependency::Dependency(::Package* package)
Dependency::~Dependency()
{
free(fName);
delete fVersion;
}
@ -34,8 +33,7 @@ Dependency::~Dependency()
status_t
Dependency::Init(const char* name)
{
fName = strdup(name);
if (fName == NULL)
if (!fName.SetTo(name))
return B_NO_MEMORY;
return B_OK;

View File

@ -12,6 +12,8 @@
#include <util/DoublyLinkedList.h>
#include "String.h"
class DependencyFamily;
class Package;
@ -52,13 +54,13 @@ public:
bool ResolvableCompatibleVersionMatches(
Version* resolvableVersion) const;
const char* Name() const { return fName; }
const String& Name() const { return fName; }
private:
::Package* fPackage;
DependencyFamily* fFamily;
::Resolvable* fResolvable;
char* fName;
String fName;
Version* fVersion;
BPackageResolvableOperator fVersionOperator;

View File

@ -20,7 +20,7 @@ public:
void AddDependenciesToList(
ResolvableDependencyList& list) const;
const char* Name() const;
String Name() const;
bool IsLastDependency(Dependency* dependency) const;
@ -58,11 +58,11 @@ DependencyFamily::AddDependenciesToList(ResolvableDependencyList& list) const
}
inline const char*
inline String
DependencyFamily::Name() const
{
Dependency* head = fDependencies.Head();
return head != NULL ? head->Name() : NULL;
return head != NULL ? head->Name() : String();
}
@ -78,22 +78,22 @@ DependencyFamily::IsLastDependency(Dependency* dependency) const
struct DependencyFamilyHashDefinition {
typedef const char* KeyType;
typedef String KeyType;
typedef DependencyFamily ValueType;
size_t HashKey(const char* key) const
size_t HashKey(const String& key) const
{
return key != NULL ? hash_hash_string(key) : 0;
return key.Hash();
}
size_t Hash(const DependencyFamily* value) const
{
return HashKey(value->Name());
return value->Name().Hash();
}
bool Compare(const char* key, const DependencyFamily* value) const
bool Compare(const String& key, const DependencyFamily* value) const
{
return strcmp(value->Name(), key) == 0;
return key == value->Name();
}
DependencyFamily*& GetLink(DependencyFamily* value) const

View File

@ -15,7 +15,7 @@ Resolvable::Resolvable(::Package* package)
:
fPackage(package),
fFamily(NULL),
fName(NULL),
fName(),
fVersion(NULL),
fCompatibleVersion(NULL)
{
@ -24,7 +24,6 @@ Resolvable::Resolvable(::Package* package)
Resolvable::~Resolvable()
{
free(fName);
delete fVersion;
delete fCompatibleVersion;
}
@ -37,8 +36,7 @@ Resolvable::Init(const char* name, ::Version* version,
fVersion = version;
fCompatibleVersion = compatibleVersion;
fName = strdup(name);
if (fName == NULL)
if (!fName.SetTo(name))
return B_NO_MEMORY;
return B_OK;

View File

@ -37,7 +37,7 @@ public:
ResolvableFamily* Family() const
{ return fFamily; }
const char* Name() const { return fName; }
const String& Name() const { return fName; }
::Version* Version() const { return fVersion; }
::Version* CompatibleVersion() const
{ return fCompatibleVersion; }
@ -50,7 +50,7 @@ public:
private:
::Package* fPackage;
ResolvableFamily* fFamily;
char* fName;
String fName;
::Version* fVersion;
::Version* fCompatibleVersion;
ResolvableDependencyList fDependencies;

View File

@ -23,7 +23,7 @@ public:
bool ResolveDependency(Dependency* dependency);
const char* Name() const;
String Name() const;
bool IsLastResolvable(Resolvable* resolvable) const;
@ -35,11 +35,11 @@ private:
};
inline const char*
inline String
ResolvableFamily::Name() const
{
Resolvable* head = fResolvables.Head();
return head != NULL ? head->Name() : NULL;
return head != NULL ? head->Name() : String();
}
@ -55,22 +55,22 @@ ResolvableFamily::IsLastResolvable(Resolvable* resolvable) const
struct ResolvableFamilyHashDefinition {
typedef const char* KeyType;
typedef String KeyType;
typedef ResolvableFamily ValueType;
size_t HashKey(const char* key) const
size_t HashKey(const String& key) const
{
return key != NULL ? hash_hash_string(key) : 0;
return key.Hash();
}
size_t Hash(const ResolvableFamily* value) const
{
return HashKey(value->Name());
return value->Name().Hash();
}
bool Compare(const char* key, const ResolvableFamily* value) const
bool Compare(const String& key, const ResolvableFamily* value) const
{
return strcmp(value->Name(), key) == 0;
return key == value->Name();
}
ResolvableFamily*& GetLink(ResolvableFamily* value) const

View File

@ -0,0 +1,34 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "String.h"
bool
String::SetToExactLength(const char* string, size_t length)
{
StringData* data = StringPool::Get(string, length);
if (data == NULL)
return false;
fData->ReleaseReference();
fData = data;
return true;
}
String&
String::operator=(const String& other)
{
if (this == &other)
return *this;
fData->ReleaseReference();
fData = other.fData;
fData->AcquireReference();
return *this;
}

View File

@ -0,0 +1,120 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STRING_H
#define STRING_H
#include "StringPool.h"
class String {
public:
String();
String(const String& other);
~String();
bool SetTo(const char* string);
bool SetTo(const char* string, size_t maxLength);
bool SetToExactLength(const char* string,
size_t length);
const char* Data() const;
uint32 Hash() const;
bool IsEmpty() const;
String& operator=(const String& other);
bool operator==(const String& other) const;
bool operator!=(const String& other) const;
operator const char*() const;
private:
StringData* fData;
};
inline
String::String()
:
fData(StringData::GetEmpty())
{
}
inline
String::String(const String& other)
:
fData(other.fData)
{
fData->AcquireReference();
}
inline
String::~String()
{
fData->ReleaseReference();
}
inline bool
String::SetTo(const char* string)
{
return SetToExactLength(string, strlen(string));
}
inline bool
String::SetTo(const char* string, size_t maxLength)
{
return SetToExactLength(string, strnlen(string, maxLength));
}
inline const char*
String::Data() const
{
return fData->String();
}
inline uint32
String::Hash() const
{
return fData->Hash();
}
inline bool
String::IsEmpty() const
{
return fData == StringData::Empty();
}
inline bool
String::operator==(const String& other) const
{
return fData == other.fData;
}
inline bool
String::operator!=(const String& other) const
{
return !(*this == other);
}
inline
String::operator const char*() const
{
return fData->String();
}
#endif // STRING_H

View File

@ -0,0 +1,58 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "StringConstants.h"
#include <new>
StringConstants StringConstants::sDefaultInstance;
/*static*/ bool
StringConstants::Init()
{
new(&sDefaultInstance) StringConstants;
if (!sDefaultInstance._Init()) {
sDefaultInstance.Cleanup();
return false;
}
return true;
}
/*static*/ void
StringConstants::Cleanup()
{
sDefaultInstance.~StringConstants();
}
bool
StringConstants::_Init()
{
// generate the member variable initializations
#define DEFINE_STRING_CONSTANT(name, value) \
if (!name.SetTo(value)) \
return false;
#define DEFINE_STRING_ARRAY_CONSTANT(name, size, ...) \
{ \
const char* const _values[size] = { __VA_ARGS__ }; \
for (size_t i = 0; i < sizeof(_values) / sizeof(_values[0]); \
i++) { \
if (!name[i].SetTo(_values[i])) \
return false; \
} \
}
#include "StringConstantsPrivate.h"
#undef DEFINE_STRING_CONSTANT
#undef DEFINE_STRING_ARRAY_CONSTANT
return true;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STRING_CONSTANTS_H
#define STRING_CONSTANTS_H
#include "AutoPackageAttributes.h"
// for the kAutoPackageAttributeNames array size
#include "String.h"
class StringConstants {
public:
// generate the member variable declarations
#define DEFINE_STRING_CONSTANT(name, value) \
String name;
#define DEFINE_STRING_ARRAY_CONSTANT(name, size, ...) \
String name[size];
#include "StringConstantsPrivate.h"
#undef DEFINE_STRING_CONSTANT
#undef DEFINE_STRING_ARRAY_CONSTANT
public:
static bool Init();
static void Cleanup();
static const StringConstants& Get()
{ return sDefaultInstance; }
private:
bool _Init();
private:
static StringConstants sDefaultInstance;
};
#endif // STRING_CONSTANTS_H

View File

@ -0,0 +1,18 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
// This file is included in StringConstants.h and StringConstants.cpp with the
// macros DEFINE_STRING[_ARRAY]_CONSTANT() defined to generate the member
// variable declarations respectively the initializations.
DEFINE_STRING_CONSTANT(kPackageLinksDirectoryName, "package-links")
DEFINE_STRING_CONSTANT(kSelfLinkName, ".self")
DEFINE_STRING_CONSTANT(kSettingsLinkName, ".settings")
DEFINE_STRING_ARRAY_CONSTANT(kAutoPackageAttributeNames,
AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT,
"SYS:PACKAGE")

View File

@ -0,0 +1,56 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STRING_KEY_H
#define STRING_KEY_H
#include "String.h"
class StringKey {
public:
StringKey(const ::String& string)
:
fString(string.Data()),
fHash(string.Hash())
{
}
explicit StringKey(const char* string)
:
fString(string),
fHash(hash_hash_string(string))
{
}
const char* String() const
{
return fString;
}
uint32 Hash() const
{
return fHash;
}
bool operator==(const ::String& other) const
{
if (fHash != other.Hash())
return false;
return fString == other.Data() || strcmp(fString, other.Data()) == 0;
}
bool operator!=(const ::String& other) const
{
return !(*this == other);
}
private:
const char* fString;
uint32 fHash;
};
#endif // STRING_KEY_H

View File

@ -0,0 +1,154 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "StringPool.h"
#include "DebugSupport.h"
static const size_t kInitialStringTableSize = 128;
static char sStringsBuffer[sizeof(StringDataHash)];
StringData StringData::fEmptyString(StringDataKey("", 0));
mutex StringPool::sLock;
StringDataHash* StringPool::sStrings;
// #pragma mark - StringData
/*static*/ void
StringData::Init()
{
new(&fEmptyString) StringData(StringDataKey("", 0));
}
// #pragma mark - StringPool
/*static*/ status_t
StringPool::Init()
{
sStrings = new(sStringsBuffer) StringDataHash;
status_t error = sStrings->Init(kInitialStringTableSize);
if (error != B_OK) {
sStrings->~StringDataHash();
sStrings = NULL;
return error;
}
mutex_init(&sLock, "string pool");
StringData::Init();
sStrings->Insert(StringData::Empty());
return B_OK;
}
/*static*/ void
StringPool::Cleanup()
{
sStrings->Remove(StringData::Empty());
sStrings->~StringDataHash();
sStrings = NULL;
mutex_destroy(&sLock);
}
/*static*/ inline StringData*
StringPool::_GetLocked(const StringDataKey& key)
{
if (StringData* string = sStrings->Lookup(key)) {
if (!string->AcquireReference())
return string;
// The object was fully dereferenced and will be deleted. Remove it
// from the hash table, so it isn't in the way.
sStrings->Remove(string);
}
return NULL;
}
/*static*/ StringData*
StringPool::Get(const char* string, size_t length)
{
MutexLocker locker(sLock);
StringDataKey key(string, length);
StringData* data = _GetLocked(key);
if (data != NULL)
return data;
locker.Unlock();
StringData* newString = StringData::Create(key);
if (newString == NULL)
return NULL;
locker.Lock();
data = _GetLocked(key);
if (data != NULL) {
locker.Unlock();
newString->Delete();
return data;
}
sStrings->Insert(newString);
return newString;
}
/*static*/ void
StringPool::LastReferenceReleased(StringData* data)
{
MutexLocker locker(sLock);
sStrings->Remove(data);
locker.Unlock();
data->Delete();
}
/*static*/ void
StringPool::DumpUsageStatistics()
{
size_t unsharedStringCount = 0;
size_t totalReferenceCount = 0;
size_t totalStringSize = 0;
size_t totalStringSizeWithDuplicates = 0;
MutexLocker locker(sLock);
for (StringDataHash::Iterator it = sStrings->GetIterator(); it.HasNext();) {
StringData* data = it.Next();
int32 referenceCount = data->CountReferences();
totalReferenceCount += referenceCount;
if (referenceCount == 1)
unsharedStringCount++;
size_t stringSize = strlen(data->String() + 1);
totalStringSize += stringSize;
totalStringSizeWithDuplicates += stringSize * referenceCount;
}
size_t stringCount = sStrings->CountElements();
size_t overhead = stringCount * (sizeof(StringData) - 1);
INFORM("StringPool usage:\n");
INFORM(" total unique strings: %8zu, %8zu bytes, overhead: %zu bytes\n",
stringCount, totalStringSize, overhead);
INFORM(" total strings with dups: %8zu, %8zu bytes\n", totalReferenceCount,
totalStringSizeWithDuplicates);
INFORM(" unshared strings: %8zu\n", unsharedStringCount);
INFORM(" bytes saved: %8zd\n",
(ssize_t)(totalStringSizeWithDuplicates - totalStringSize - overhead));
}

View File

@ -0,0 +1,192 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STRING_POOL_H
#define STRING_POOL_H
#include <SupportDefs.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include <util/AutoLock.h>
#include <util/khash.h>
#include <util/OpenHashTable.h>
class StringData;
class StringDataKey {
public:
StringDataKey(const char* string, size_t length)
:
fString(string),
fLength(length),
fHash(hash_hash_string_part(string, length))
{
}
const char* String() const
{
return fString;
}
size_t Length() const
{
return fLength;
}
uint32 Hash() const
{
return fHash;
}
private:
const char* fString;
size_t fLength;
uint32 fHash;
};
struct StringDataHashDefinition;
typedef BOpenHashTable<StringDataHashDefinition> StringDataHash;
class StringPool {
public:
static status_t Init();
static void Cleanup();
static StringData* Get(const char* string, size_t length);
static void LastReferenceReleased(StringData* data);
static void DumpUsageStatistics();
private:
static StringData* _GetLocked(const StringDataKey& key);
private:
static mutex sLock;
static StringDataHash* sStrings;
};
class StringData {
public:
static void Init();
static StringData* Create(const StringDataKey& key)
{
void* data = malloc(sizeof(StringData) + key.Length());
if (data == NULL)
return NULL;
return new(data) StringData(key);
}
static StringData* Empty()
{
return &fEmptyString;
}
static StringData* GetEmpty()
{
fEmptyString.AcquireReference();
return &fEmptyString;
}
void Delete()
{
free(this);
}
bool AcquireReference()
{
return atomic_add(&fReferenceCount, 1) == 0;
}
void ReleaseReference()
{
if (atomic_add(&fReferenceCount, -1) == 1)
StringPool::LastReferenceReleased(this);
}
// debugging only
int32 CountReferences() const
{
return fReferenceCount;
}
const char* String() const
{
return fString;
}
uint32 Hash() const
{
return fHash;
}
StringData*& HashNext()
{
return fHashNext;
}
private:
StringData(const StringDataKey& key)
:
fReferenceCount(1),
fHash(key.Hash())
{
memcpy(fString, key.String(), key.Length());
fString[key.Length()] = '\0';
}
~StringData()
{
}
private:
static StringData fEmptyString;
StringData* fHashNext;
int32 fReferenceCount;
uint32 fHash;
char fString[1];
};
struct StringDataHashDefinition {
typedef StringDataKey KeyType;
typedef StringData ValueType;
size_t HashKey(const StringDataKey& key) const
{
return key.Hash();
}
size_t Hash(const StringData* value) const
{
return value->Hash();
}
bool Compare(const StringDataKey& key, const StringData* value) const
{
return key.Hash() == value->Hash()
&& strncmp(value->String(), key.String(), key.Length()) == 0
&& value->String()[key.Length()] == '\0';
}
StringData*& GetLink(StringData* value) const
{
return value->HashNext();
}
};
#endif // STRING_POOL_H

View File

@ -22,11 +22,11 @@ static const char* const kVersionPartPlaceholder = "_";
static int
compare_version_part(const char* a, const char* b)
compare_version_part(const String& a, const String& b)
{
if (a == NULL)
return b != NULL ? -1 : 0;
if (b == NULL)
if (a.IsEmpty())
return b.IsEmpty() ? 0 : -1;
if (b.IsEmpty())
return 1;
return BPrivate::NaturalCompare(a, b);
@ -35,10 +35,10 @@ compare_version_part(const char* a, const char* b)
Version::Version()
:
fMajor(NULL),
fMinor(NULL),
fMicro(NULL),
fPreRelease(NULL),
fMajor(),
fMinor(),
fMicro(),
fPreRelease(),
fRevision(0)
{
}
@ -46,10 +46,6 @@ Version::Version()
Version::~Version()
{
free(fMajor);
free(fMinor);
free(fMicro);
free(fPreRelease);
}
@ -58,26 +54,22 @@ Version::Init(const char* major, const char* minor, const char* micro,
const char* preRelease, uint32 revision)
{
if (major != NULL) {
fMajor = strdup(major);
if (fMajor == NULL)
if (!fMajor.SetTo(major))
return B_NO_MEMORY;
}
if (minor != NULL) {
fMinor = strdup(minor);
if (fMinor == NULL)
if (!fMinor.SetTo(minor))
return B_NO_MEMORY;
}
if (micro != NULL) {
fMicro = strdup(micro);
if (fMicro == NULL)
if (!fMicro.SetTo(micro))
return B_NO_MEMORY;
}
if (preRelease != NULL) {
fPreRelease = strdup(preRelease);
if (fPreRelease == NULL)
if (!fPreRelease.SetTo(preRelease))
return B_NO_MEMORY;
}
@ -124,10 +116,10 @@ Version::Compare(const Version& other) const
// The pre-version works differently: The empty string is greater than any
// non-empty string (e.g. "R1" is newer than "R1-rc2"). So we catch the
// empty string cases first.
if (fPreRelease == NULL) {
if (other.fPreRelease != NULL)
if (fPreRelease.IsEmpty()) {
if (!other.fPreRelease.IsEmpty())
return 1;
} else if (other.fPreRelease == NULL) {
} else if (other.fPreRelease.IsEmpty()) {
return -1;
} else {
// both are non-null -- compare normally
@ -180,27 +172,27 @@ Version::ToString(char* buffer, size_t bufferSize) const
const char* minor = fMinor;
const char* micro = fMicro;
if (micro != NULL && minor == NULL)
if (micro[0] != '\0' && minor[0] == '\0')
minor = kVersionPartPlaceholder;
if (minor != NULL && major == NULL)
if (minor[0] != '\0' && major[0] == '\0')
major = kVersionPartPlaceholder;
size_t size = strlcpy(buffer, major, bufferSize);
if (minor != NULL) {
if (minor[0] != '\0') {
size_t offset = std::min(bufferSize, size);
size += snprintf(buffer + offset, bufferSize - offset, ".%s", minor);
}
if (micro != NULL) {
if (micro[0] != '\0') {
size_t offset = std::min(bufferSize, size);
size += snprintf(buffer + offset, bufferSize - offset, ".%s", micro);
}
if (fPreRelease != NULL) {
if (fPreRelease[0] != '\0') {
size_t offset = std::min(bufferSize, size);
size += snprintf(buffer + offset, bufferSize - offset, "~%s",
fPreRelease);
fPreRelease.Data());
}
if (fRevision != 0) {

View File

@ -9,6 +9,8 @@
#include <package/PackageResolvableOperator.h>
#include <SupportDefs.h>
#include "String.h"
using namespace BPackageKit;
@ -35,10 +37,10 @@ public:
// been (excluding the terminating null)
private:
char* fMajor;
char* fMinor;
char* fMicro;
char* fPreRelease;
String fMajor;
String fMinor;
String fMicro;
String fPreRelease;
uint32 fRevision;
};

View File

@ -16,7 +16,7 @@ OldNodeAttributes::~OldNodeAttributes()
void*
OldNodeAttributes::IndexCookieForAttribute(const char* name) const
OldNodeAttributes::IndexCookieForAttribute(const StringKey& name) const
{
return NULL;
}

View File

@ -11,6 +11,8 @@
#include <util/DoublyLinkedList.h>
#include <util/OpenHashTable.h>
#include "StringKey.h"
class Node;
@ -24,7 +26,8 @@ public:
virtual timespec ModifiedTime() const = 0;
virtual off_t FileSize() const = 0;
virtual void* IndexCookieForAttribute(const char* name) const;
virtual void* IndexCookieForAttribute(const StringKey& name)
const;
};

View File

@ -12,6 +12,7 @@
#include "DebugSupport.h"
#include "PackageLinksDirectory.h"
#include "StringConstants.h"
//#define TRACE_DEPENDENCIES_ENABLED
@ -22,9 +23,6 @@
#endif
static const char* const kPackageLinksDirectoryName = "package-links";
mutex PackageFSRoot::sRootListLock = MUTEX_INITIALIZER("packagefs root list");
PackageFSRoot::RootList PackageFSRoot::sRootList;
@ -71,7 +69,7 @@ PackageFSRoot::Init()
return B_NO_MEMORY;
status_t error = fPackageLinksDirectory->Init(NULL,
kPackageLinksDirectoryName, 0);
StringConstants::Get().kPackageLinksDirectoryName);
if (error != B_OK)
RETURN_ERROR(error);
@ -243,7 +241,7 @@ PackageFSRoot::_RemoveVolume(Volume* volume)
status_t
PackageFSRoot::_AddPackage(Package* package)
{
TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name());
TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name().Data());
ResolvableDependencyList dependenciesToUpdate;
@ -306,7 +304,7 @@ PackageFSRoot::_AddPackage(Package* package)
void
PackageFSRoot::_RemovePackage(Package* package)
{
TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name());
TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name().Data());
fPackageLinksDirectory->RemovePackage(package);

View File

@ -485,12 +485,16 @@ Volume::Mount(const char* parameterString)
}
}
String volumeNameString;
if (!volumeNameString.SetTo(volumeName))
RETURN_ERROR(B_NO_MEMORY);
// create the root node
fRootDirectory
= new(std::nothrow) ::RootDirectory(kRootDirectoryID, st.st_mtim);
if (fRootDirectory == NULL)
RETURN_ERROR(B_NO_MEMORY);
fRootDirectory->Init(NULL, volumeName, 0);
fRootDirectory->Init(NULL, volumeNameString);
fNodes.Insert(fRootDirectory);
fRootDirectory->AcquireReference();
// one reference for the table
@ -529,6 +533,8 @@ Volume::Mount(const char* parameterString)
if (error != B_OK)
RETURN_ERROR(error);
StringPool::DumpUsageStatistics();
return B_OK;
}
@ -1318,7 +1324,7 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
status_t
Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name,
Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const String& name,
UnpackingNode*& _node)
{
UnpackingNode* unpackingNode;
@ -1335,7 +1341,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name,
Node* node = unpackingNode->GetNode();
BReference<Node> nodeReference(node, true);
status_t error = node->Init(parent, name, 0);
status_t error = node->Init(parent, name);
if (error != B_OK)
RETURN_ERROR(error);
@ -1541,7 +1547,7 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
oldPackageReferences[oldPackageIndex++].SetTo(package);
_RemovePackageContent(package, NULL, true);
_RemovePackage(package);
INFORM("package \"%s\" deactivated\n", package->FileName());
INFORM("package \"%s\" deactivated\n", package->FileName().Data());
}
// TODO: Since package removal cannot fail, consider adding the new packages
// first. The reactivation case may make that problematic, since two packages
@ -1560,7 +1566,7 @@ INFORM("package \"%s\" deactivated\n", package->FileName());
_RemovePackage(package);
break;
}
INFORM("package \"%s\" activated\n", package->FileName());
INFORM("package \"%s\" activated\n", package->FileName().Data());
}
// Try to roll back the changes, if an error occurred.
@ -1579,7 +1585,7 @@ INFORM("package \"%s\" activated\n", package->FileName());
// nothing we can do here
ERROR("Volume::_ChangeActivation(): failed to roll back "
"deactivation of package \"%s\" after error\n",
package->FileName());
package->FileName().Data());
_RemovePackage(package);
}
}
@ -1619,7 +1625,11 @@ Volume::_CreateShineThroughDirectory(Directory* parent, const char* name,
RETURN_ERROR(B_NO_MEMORY);
BReference<ShineThroughDirectory> directoryReference(directory, true);
status_t error = directory->Init(parent, name, 0);
String nameString;
if (!nameString.SetTo(name))
RETURN_ERROR(B_NO_MEMORY);
status_t error = directory->Init(parent, nameString);
if (error != B_OK)
RETURN_ERROR(error);

View File

@ -85,7 +85,7 @@ public:
const void* oldKey, size_t oldLength,
const void* newKey, size_t newLength);
Index* FindIndex(const char* name) const
Index* FindIndex(const StringKey& name) const
{ return fIndices.Lookup(name); }
IndexDirIterator GetIndexDirIterator() const
{ return fIndices.GetIterator(); }
@ -139,7 +139,7 @@ private:
bool notify);
status_t _CreateUnpackingNode(mode_t mode,
Directory* parent, const char* name,
Directory* parent, const String& name,
UnpackingNode*& _node);
// does *not* return a reference
void _RemoveNode(Node* node);