]> git.saurik.com Git - cydia.git/commitdiff
Replace 99.9% of metadata.plist with metadata.cb0.
authorJay Freeman (saurik) <saurik@saurik.com>
Tue, 30 Nov 2010 11:59:09 +0000 (03:59 -0800)
committerJay Freeman (saurik) <saurik@saurik.com>
Tue, 30 Nov 2010 22:37:50 +0000 (14:37 -0800)
Cytore.hpp [new file with mode: 0644]
MobileCydia.mm
makefile

diff --git a/Cytore.hpp b/Cytore.hpp
new file mode 100644 (file)
index 0000000..62e956c
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright Notice (GNU Affero GPL) {{{
+/* Cyndir - (Awesome) Memory Mapped Dictionary
+ * Copyright (C) 2010  Jay Freeman (saurik)
+*/
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+// }}}
+
+#ifndef CYTORE_HPP
+#define CYTORE_HPP
+
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <cstdio>
+#include <cstdlib>
+
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define _assert(test) do \
+    if (!(test)) { \
+        fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
+        exit(-1); \
+    } \
+while (false)
+
+namespace Cytore {
+
+static const uint32_t Magic = 'cynd';
+
+struct Header {
+    uint32_t magic_;
+    uint32_t version_;
+    uint32_t size_;
+    uint32_t reserved_;
+};
+
+struct Block {
+};
+
+template <typename Target_>
+class Offset {
+  private:
+    uint32_t offset_;
+
+  public:
+    Offset() :
+        offset_(0)
+    {
+    }
+
+    Offset(uint32_t offset) :
+        offset_(offset)
+    {
+    }
+
+    Offset &operator =(uint32_t offset) {
+        offset_ = offset;
+        return *this;
+    }
+
+    uint32_t GetOffset() const {
+        return offset_;
+    }
+
+    bool IsNull() const {
+        return offset_ == 0;
+    }
+};
+
+template <typename Type_>
+static _finline Type_ Round(Type_ value, Type_ size) {
+    Type_ mask(size - 1);
+    return value + mask & ~mask;
+}
+
+template <typename Base_>
+class File {
+  private:
+    static const unsigned Shift_ = 17;
+    static const size_t Block_ = 1 << Shift_;
+    static const size_t Mask_ = Block_ - 1;
+
+  private:
+    int file_;
+    std::vector<uint8_t *> blocks_;
+
+    Header &Header_() {
+        return *reinterpret_cast<Header *>(blocks_[0]);
+    }
+
+    uint32_t &Size_() {
+        return Header_().size_;
+    }
+
+    void Map_(size_t size) {
+        size_t before(blocks_.size() * Block_);
+        size_t extend(size - before);
+
+        void *data(mmap(NULL, extend, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, file_, before));
+        for (size_t i(0); i != extend >> Shift_; ++i)
+            blocks_.push_back(reinterpret_cast<uint8_t *>(data) + Block_ * i);
+    }
+
+    void Truncate_(size_t capacity) {
+        capacity = Round(capacity, Block_);
+        ftruncate(file_, capacity);
+        Map_(capacity);
+    }
+
+  public:
+    File() :
+        file_(-1)
+    {
+    }
+
+    File(const char *path) :
+        file_(-1)
+    {
+        Open(path);
+    }
+
+    ~File() {
+        // XXX: this object is never deconstructed. if it were, this should unmap the memory
+        close(file_);
+    }
+
+    size_t Capacity() const {
+        return blocks_.size() * Block_;
+    }
+
+    void Open(const char *path) {
+        _assert(file_ == -1);
+        file_ = open(path, O_RDWR | O_CREAT | O_EXLOCK, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+        struct stat stat;
+        fstat(file_, &stat);
+
+        size_t core(sizeof(Header) + sizeof(Base_));
+
+        size_t size(stat.st_size);
+        if (size == 0) {
+            Truncate_(core);
+            Header_().magic_ = Magic;
+            Size_() = core;
+        } else {
+            _assert(size >= core);
+            Truncate_(size);
+            _assert(Header_().magic_ == Magic);
+            _assert(Header_().version_ == 0);
+        }
+    }
+
+    void Reserve(size_t capacity) {
+        if (capacity <= Capacity())
+            return;
+        blocks_.pop_back();
+        Truncate_(capacity);
+    }
+
+    template <typename Target_>
+    Target_ &Get(uint32_t offset) {
+        return *reinterpret_cast<Target_ *>(blocks_[offset >> Shift_] + (offset & Mask_));
+    }
+
+    template <typename Target_>
+    Target_ &Get(Offset<Target_> &ref) {
+        return Get<Target_>(ref.GetOffset());
+    }
+
+    Base_ *operator ->() {
+        return &Get<Base_>(sizeof(Header));
+    }
+
+    template <typename Target_>
+    Offset<Target_> New(size_t extra = 0) {
+        size_t size(sizeof(Target_) + extra);
+        size = Round(size, sizeof(uintptr_t));
+        Reserve(Size_() + size);
+        uint32_t offset(Size_());
+        Size_() += size;
+        return Offset<Target_>(offset);
+    }
+};
+
+}
+
+#endif//CYTORE_HPP
index 3ec3cebaeba70646efa01f3da64f6ef34fb93d0b..29fe2ae18c57bd710be6a7d110d8f001ca7e8151 100644 (file)
@@ -118,6 +118,8 @@ extern "C" {
 #include <errno.h>
 #include <pcre.h>
 
+#include <Cytore.hpp>
+
 #include "UICaboodle/BrowserView.h"
 
 #include "substrate.h"
@@ -202,6 +204,15 @@ void PrintTimes() {
     while (false); \
     [_pool release];
 
+// Hash Functions/Structures {{{
+extern "C" uint32_t hashlittle(const void *key, size_t length, uint32_t initval = 0);
+
+union SplitHash {
+    uint32_t u32;
+    uint16_t u16[2];
+};
+// }}}
+
 static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
 
 void NSLogPoint(const char *fix, const CGPoint &point) {
@@ -1410,6 +1421,106 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 @end
 /* }}} */
 
+// Cytore Definitions {{{
+struct PackageValue :
+    Cytore::Block
+{
+    Cytore::Offset<void> reserved_;
+    Cytore::Offset<PackageValue> next_;
+
+    uint32_t index_ : 23;
+    uint32_t subscribed_ : 1;
+    uint32_t : 8;
+
+    int32_t first_;
+    int32_t last_;
+
+    uint16_t vhash_;
+    uint16_t nhash_;
+
+    char version_[8];
+    char name_[];
+};
+
+struct MetaValue :
+    Cytore::Block
+{
+    Cytore::Offset<void> reserved_;
+    Cytore::Offset<PackageValue> packages_[1 << 16];
+};
+
+static Cytore::File<MetaValue> MetaFile_;
+// }}}
+// Cytore Helper Functions {{{
+static PackageValue *PackageFind(const char *name, size_t length, Cytore::Offset<PackageValue> *cache = NULL) {
+    SplitHash nhash = { hashlittle(name, length) };
+
+    PackageValue *metadata;
+
+    Cytore::Offset<PackageValue> *offset(&MetaFile_->packages_[nhash.u16[0]]);
+    offset: if (offset->IsNull()) {
+        *offset = MetaFile_.New<PackageValue>(length + 1);
+        metadata = &MetaFile_.Get(*offset);
+
+        memcpy(metadata->name_, name, length + 1);
+        metadata->nhash_ = nhash.u16[1];
+    } else {
+        metadata = &MetaFile_.Get(*offset);
+
+        if (metadata->nhash_ != nhash.u16[1] || strncmp(metadata->name_, name, length + 1) != 0) {
+            offset = &metadata->next_;
+            goto offset;
+        }
+    }
+
+    if (cache != NULL)
+        *cache = *offset;
+
+    return metadata;
+}
+
+static void PackageImport(const void *key, const void *value, void *context) {
+    char buffer[1024];
+    if (!CFStringGetCString((CFStringRef) key, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
+        NSLog(@"failed to import package %@", key);
+        return;
+    }
+
+    PackageValue *metadata(PackageFind(buffer, strlen(buffer)));
+    NSDictionary *package((NSDictionary *) value);
+
+    if (NSNumber *subscribed = [package objectForKey:@"IsSubscribed"])
+        if ([subscribed boolValue])
+            metadata->subscribed_ = true;
+
+    if (NSDate *date = [package objectForKey:@"FirstSeen"]) {
+        time_t time([date timeIntervalSince1970]);
+        if (metadata->first_ > time || metadata->first_ == 0)
+            metadata->first_ = time;
+    }
+
+    if (NSDate *date = [package objectForKey:@"LastSeen"]) {
+        time_t time([date timeIntervalSince1970]);
+        if (metadata->last_ < time || metadata->last_ == 0) {
+            metadata->last_ = time;
+            goto last;
+        }
+    } else if (metadata->last_ == 0) last: {
+        NSString *version([package objectForKey:@"LastVersion"]);
+        if (CFStringGetCString((CFStringRef) version, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
+            size_t length(strlen(buffer));
+            uint16_t vhash(hashlittle(buffer, length));
+
+            size_t capped(std::min<size_t>(8, length));
+            char *latest(buffer + length - capped);
+
+            strncpy(metadata->version_, latest, sizeof(metadata->version_));
+            metadata->vhash_ = vhash;
+        }
+    }
+}
+// }}}
+
 /* Source Class {{{ */
 @interface Source : NSObject {
     CYString depiction_;
@@ -1735,10 +1846,8 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
     NSMutableArray *tags_;
     NSString *role_;
 
-    NSMutableDictionary *metadata_;
-    time_t firstSeen_;
-    time_t lastSeen_;
-    bool subscribed_;
+    Cytore::Offset<PackageValue> metadata_;
+
     bool ignored_;
 }
 
@@ -1762,9 +1871,12 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 - (NSString *) shortDescription;
 - (unichar) index;
 
-- (NSMutableDictionary *) metadata;
+- (PackageValue *) metadata;
 - (time_t) seen;
-- (BOOL) subscribed;
+
+- (bool) subscribed;
+- (bool) setSubscribed:(bool)subscribed;
+
 - (BOOL) ignored;
 
 - (NSString *) latest;
@@ -1972,9 +2084,6 @@ struct PackageNameOrdering :
     if (role_ != nil)
         [role_ release];
 
-    if (metadata_ != nil)
-        [metadata_ release];
-
     [super dealloc];
 }
 
@@ -2123,52 +2232,26 @@ struct PackageNameOrdering :
             }
         _end
 
-        bool changed(false);
-
         _profile(Package$initWithVersion$Metadata)
-            metadata_ = [Packages_ objectForKey:id_];
-
-            if (metadata_ == nil) {
-                firstSeen_ = now_;
+            PackageValue *metadata(PackageFind(id_.data(), id_.size(), &metadata_));
 
-                metadata_ = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
-                    [NSDate dateWithTimeIntervalSince1970:firstSeen_], @"FirstSeen",
-                    static_cast<id>(latest_), @"LastVersion",
-                nil] mutableCopy];
+            const char *latest(version_.VerStr());
+            size_t length(strlen(latest));
 
-                changed = true;
-            } else {
-                firstSeen_ = [[metadata_ objectForKey:@"FirstSeen"] timeIntervalSince1970];
-                lastSeen_ = [[metadata_ objectForKey:@"LastSeen"] timeIntervalSince1970];
+            uint16_t vhash(hashlittle(latest, length));
 
-                if (NSNumber *subscribed = [metadata_ objectForKey:@"IsSubscribed"])
-                    subscribed_ = [subscribed boolValue];
+            size_t capped(std::min<size_t>(8, length));
+            latest = latest + length - capped;
 
-                NSString *version([metadata_ objectForKey:@"LastVersion"]);
+            if (metadata->first_ == 0)
+                metadata->first_ = now_;
 
-                if (firstSeen_ == 0) {
-                    firstSeen_ = lastSeen_ == 0 ? now_ : lastSeen_;
-                    [metadata_ setObject:[NSDate dateWithTimeIntervalSince1970:firstSeen_] forKey:@"FirstSeen"];
-                    changed = true;
-                }
-
-                if (version == nil) {
-                    [metadata_ setObject:latest_ forKey:@"LastVersion"];
-                    changed = true;
-                } else if (![version isEqualToString:latest_]) {
-                    [metadata_ setObject:latest_ forKey:@"LastVersion"];
-                    lastSeen_ = now_;
-                    [metadata_ setObject:[NSDate dateWithTimeIntervalSince1970:lastSeen_] forKey:@"LastSeen"];
-                    changed = true;
-                }
-            }
-
-            metadata_ = [metadata_ retain];
-
-            if (changed) {
-                [Packages_ setObject:metadata_ forKey:id_];
-                Changed_ = true;
-            }
+            if (metadata->vhash_ != vhash || strncmp(metadata->version_, latest, sizeof(metadata->version_)) != 0) {
+                metadata->last_ = now_;
+                strncpy(metadata->version_, latest, sizeof(metadata->version_));
+                metadata->vhash_ = vhash;
+            } else if (metadata->last_ == 0)
+                metadata->last_ = metadata->first_;
         _end
 
         _profile(Package$initWithVersion$Section)
@@ -2303,16 +2386,25 @@ struct PackageNameOrdering :
     _end
 }
 
-- (NSMutableDictionary *) metadata {
-    return metadata_;
+- (PackageValue *) metadata {
+    return &MetaFile_.Get(metadata_);
 }
 
 - (time_t) seen {
-    return subscribed_ ? lastSeen_ : firstSeen_;
+    PackageValue *metadata([self metadata]);
+    return metadata->subscribed_ ? metadata->last_ : metadata->first_;
 }
 
-- (BOOL) subscribed {
-    return subscribed_;
+- (bool) subscribed {
+    return [self metadata]->subscribed_;
+}
+
+- (bool) setSubscribed:(bool)subscribed {
+    PackageValue *metadata([self metadata]);
+    if (metadata->subscribed_ == subscribed)
+        return false;
+    metadata->subscribed_ = subscribed;
+    return true;
 }
 
 - (BOOL) ignored {
@@ -7205,34 +7297,19 @@ freeing the view controllers on tab change */
     if (package_ == nil)
         return 0;
 
-    return 1;
+    return 2;
 }
 
 - (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
     return UCLocalize("SHOW_ALL_CHANGES_EX");
 }
 
-- (void) onSomething:(BOOL)value withKey:(NSString *)key {
+- (void) onSubscribed:(id)control {
+    bool value([control isOn]);
     if (package_ == nil)
         return;
-
-    NSMutableDictionary *metadata([package_ metadata]);
-
-    BOOL before;
-    if (NSNumber *number = [metadata objectForKey:key])
-        before = [number boolValue];
-    else
-        before = NO;
-
-    if (value != before) {
-        [metadata setObject:[NSNumber numberWithBool:value] forKey:key];
-        Changed_ = true;
+    if ([package_ setSubscribed:value])
         [delegate_ updateData];
-    }
-}
-
-- (void) onSubscribed:(id)control {
-    [self onSomething:(int) [control isOn] withKey:@"IsSubscribed"];
 }
 
 - (void) onIgnored:(id)control {
@@ -9001,11 +9078,6 @@ int main(int argc, char *argv[]) { _pooled
     if (Settings_ != nil)
         Role_ = [Settings_ objectForKey:@"Role"];
 
-    if (Packages_ == nil) {
-        Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
-        [Metadata_ setObject:Packages_ forKey:@"Packages"];
-    }
-
     if (Sections_ == nil) {
         Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
         [Metadata_ setObject:Sections_ forKey:@"Sections"];
@@ -9017,6 +9089,18 @@ int main(int argc, char *argv[]) { _pooled
     }
     /* }}} */
 
+    _trace();
+    MetaFile_.Open("/var/lib/cydia/metadata.cb0");
+    _trace();
+
+    if (Packages_ != nil) {
+        CFDictionaryApplyFunction((CFDictionaryRef) Packages_, &PackageImport, NULL);
+        _trace();
+        [Metadata_ removeObjectForKey:@"Packages"];
+        Packages_ = nil;
+        Changed_ = true;
+    }
+
     Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
 
     if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/SimulatedKeyEvents.dylib", F_OK) == 0)
index 5868accc9bbf09d64f58a32744cc9bcefc14bbcf..89c43b270a2968bb670bcbce6be4d454ca187dab 100644 (file)
--- a/makefile
+++ b/makefile
@@ -56,7 +56,7 @@ clean:
 %.o: %.c
        $(cycc) -c -o $@ -x c $<
 
-MobileCydia: MobileCydia.mm UICaboodle/*.h UICaboodle/*.mm iPhonePrivate.h lookup3.o
+MobileCydia: MobileCydia.mm UICaboodle/*.h UICaboodle/*.mm iPhonePrivate.h lookup3.o Cytore.hpp
        $(cycc) $(filter %.mm,$^) $(filter %.o,$^) $(flags) $(link) $(uikit)
        ldid -Slaunch.xml $@ || { rm -f $@ && false; }