GithubHelp home page GithubHelp logo

mochidev / codabledatastore Goto Github PK

View Code? Open in Web Editor NEW
16.0 2.0 1.0 437 KB

An ACID-compliant database written in pure-swift enabling on-disk persistence for apps and services.

License: MIT License

Swift 100.00%
database ios linux macos swift swift-async swift-package-manager swift-server swift5-9 tvos

codabledatastore's People

Contributors

dimitribouniol avatar pnewell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

pnewell

codabledatastore's Issues

Persist methods should return their old values

As it says on the tin, when persisting an instance, the old instance should be returned, especially since we have it already. Same for deletes actually (it only does this when deleting ids).

In-process registry of open disk persistences

We should utilize an in-process registry to ensure that only one disk persistence for a given URL is used at once, logging to make sure a developer doesn't inadvertently create a second instance.

Create a dedicated actor for DiskIO

This should have a static method that takes a url, and returns a shared actor for the volume the URL resides on. This way, all synchronous IO can be isolated to a single actor. Additionally, when running with the 5.9 runtime, we should use a custom executor to grab a new thread for that IO rather than use the swift concurrency pool, since it would eat up a slot otherwise.

Indexed values should be required to conform to IndexComparable

This protocol should return an agnostic representation of a comparable structure in a format that the datastore natively understands. Take a look at foundation db for inspiration, as their binary key paths could be a good format. However, since the goal is to still have human readable files on disk, the default format could be an array of enum primitives to be sorted accordingly? One benefit to Comparable is the ability to add new sorting capabilities, so some investigation should be placed into supporting that well.

Provide better support for mismatched versions during migrations

ie. offer to manually migrate from a known old version type to a new one. This can be useful if the version was initially an Int, but became a String down the line. Currently, the only way around this would be to have an initializer for the old representation in the new type than evaluates to some deprecated, low-sorting version.

Indexes containing dates may not be updatable or deletable

The Date in the index is encoded with milliseconds precision, but this may not match the in memory representation nor the persisted representation. For not, don't use indexes involving floats.

To fix, a) have a stable index representation as in #176, and b) make sure primary record points back to indexed entries. (This might be catastrophic for entries whose identifier is a float…)

Consider flipping data and decoder in migrations

Currently, when defining migrations using the shorthand $0/1 syntax, the data and decoder is used in the opposite order:

    static func datastore(for persistence: DiskPersistence<ReadWrite>) -> Datastore {
        .JSONStore(
            persistence: persistence,
            key: datastoreKey,
            version: .zero,
            migrations: [
                .zero: { try $1.decode(KeyValue.self, from: $0) }
            ]
        )
    }

Load on an empty datastore fails

If you attempt to load a value when the datastore has no root object, a DatastoreInterfaceError.datastoreKeyNotFound error will be thrown instead of nil.

Manifests should be paged

It's currently possible to accumulate many manifest files, so they should probably be paged to not bring down file system performance.

Add sparse set lookups

Given a sorted set of IDs (or index entries), we should be able to efficiently walk the tree gathering records in the process, skipping pages as we go.

Add support for Many to One indexes

A persisted type might be available under multiple index entries, and it might be useful to load them as such, especially when we aren't loading a range of index values, but discrete IDs instead.

Add .exact to IndexRangeExpression

Sometimes we are only ever interested in a single value. That said, perhaps a special index type can help here, which would inform the generics of the accessors.

Support static properties for default disk stores

It would be much nicer to get a single common instance when getting the default store:

extension DiskPersistence where AccessMode == ReadWrite {
    /// The default persistence for the read-write store of an app.
    public static var `default`: DiskPersistence<AccessMode> = ...
}

extension DiskPersistence where AccessMode == ReadOnly {
    /// The default persistence for the read-only store of an app.
    public static var readOnlyDefault: DiskPersistence<AccessMode> = self.default.readOnly
}

However, the default URL helper cannot through in that case, specifically on Linux, and we must have a way from converting from a read-write store to a read-only one.

Depends on:

Error "Is a directory" when reopening existing store

I've been getting the following error any time I try to reinitialize a store that was previously created. Creating and using a store the first time always works, but if I try to reuse the same URL when rebuilding it always fails with this error:

CodableDatastoreTest/CodableDatastoreTestApp.swift:18: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “2023-07-13 20-58-15 29023E6541A4E39A.snapshot” couldn’t be opened." UserInfo={NSFilePath=/Users/_______/Library/Developer/CoreSimulator/Devices/B6EABA41-EBF0-46A4-8A33-0150DDA84DD2/data/Containers/Data/Application/505B0923-E569-441A-862C-351FA816B866/tmp/73B58D72-6462-4C31-B5B9-FF5DCF5C085F-19496-000005FDA764CEDA/Snapshots/2023/07-13/20-58/2023-07-13 20-58-15 29023E6541A4E39A.snapshot, NSUnderlyingError=0x600000c98660 {Error Domain=NSPOSIXErrorDomain Code=21 "Is a directory"}}

I even copied the DiskPersistenceDatastoreTests file and tried to run it twice with a static URL and get the same error

Example func that works the first time and successfully persists and then fails with above error when trying to build and run a second time

func write() {
        let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.pnewelljr.CodableDatastoreTest")!.appending(path: "Store", directoryHint: .isDirectory)
        let persistence = try DiskPersistence(readWriteURL: url)
        try await persistence.createPersistenceIfNecessary()

        let datastore = Datastore.JSONStore(
            persistence: persistence,
            key: "test",
            version: Version.zero,
            migrations: [
                .zero: { data, decoder in
                    try decoder.decode(TestStruct.self, from: data)
                }
            ]
        )
       try await datastore.warm()
      
        
        try await datastore.persist(TestStruct(id: "3", value: "My name is Dimitri"))
        try await datastore.persist(TestStruct(id: "1", value: "Hello, World!"))
        try await datastore.persist(TestStruct(id: "2", value: "Twenty Three is Number One"))

        let count = try await datastore.count
}

Rename load(_ range:)

We should rename load(_ range:) to load(_ idRange:) to make it clear to code completion results that this is not for the regular indexed fields.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.