mbdavid / LiteDB

LiteDB - A .NET NoSQL Document Store in a single data file
http://www.litedb.org
MIT License
8.61k stars 1.25k forks source link

[BUG] #1616

Open qart2003 opened 4 years ago

qart2003 commented 4 years ago

Hello @mbdavid , I have project with 20 LiteDB dbs 4.1.4 version. All works fine, were stable and predictable State: I convert it to 5.. version which download from github cos it convert objects with fields which equal null. Get: Code runs with error in FileStreamFactory: the file is using by other thread, but its immposible. I even restarted computer, not only vs. [var stream = new FileStream(_filename, IN public Stream GetStream(bool canWrite, bool sequencial)]. What do I wrong?

lbnascimento commented 4 years ago

@qart2003 Could you provide some sample code showing how you're opening and using your datafiles?

qart2003 commented 4 years ago

Hello. I did it (refactoring and different improves), moved 20+ dbs to v5 (they have smaller size then in v4) and have new questions: Is db proccess safe? - No Is db thread safe? - yes but I worked with v4 in this way:

In DAL

abstract public class BasicArticlesDataMapper
{
    static protected LiteDB.LiteDatabase d_writer = null;

    public string ConnectionString { get; set; }

    public BasicArticlesDataMapper(string CStr)
    {
        ConnectionString = CStr;
        if (d_writer == null)
            d_writer = new LiteDB.LiteDatabase(CStr);
    }
}

In SL

public abstract class ArticlesServiceBase
{
    public string ConnectionString { get; set; }

    protected ArticlesServiceBase(string connectionString)
    {
        ConnectionString = connectionString;
    }

    private ArticleDataMapper _articleDataMapper;

    protected ArticleDataMapper ArticleDataMapper
    {
        get
        {
            return _articleDataMapper ??
                   (_articleDataMapper = new ArticleDataMapper(ConnectionString));
        }
    }
}

And in any place where I need in ArticleService, I create it and use and all works fine exclude Data not added into db, all works without errors. Is it depends with transaction of v5 or what do I wrong?

lbnascimento commented 4 years ago

@qart2003 Could you post the exact error message you're getting and the stack trace? Also, is there any reason for the BasicArticlesDataMapper constructor to overwrite d_writer, which is a static attribute?

qart2003 commented 4 years ago

I get no error, but added item is absent The static is for using in any place ViewSomeItem.cs contain lines SomeItemService someItemService = new SomeItemService(VarStore.fnDbSomeItems); I shoud use the one LiteDatabase object for any collection in current DB (it worked fine for v4), its about unit of work pattern, probably not best implementation but its UOW. I have some dbs for different biz objects like newsItem, articlesItem, HoroscopeItem and so on. And when I use the one service object from VarStore (or from DI like singleton way) I get ok with modify data (add/edit newsItem was added - ok). Implementations are fully equal for DAL/SL (different dbs for functional paritions for prefomance, I can show site, its not secret but its in russian)

lbnascimento commented 4 years ago

@qart2003 Could you show me an example of how you're opening collections and making the insertions?

qart2003 commented 4 years ago

I'm working with LiteDB from V2, when it was without ReaderWriterLockSlim inside. The Like next code worked fine from v3-v4 I fixed error but dont know why? I just in UI dll create HoroService once and use this object in every place.

namespace JApp.DAL.Horo { abstract public class HoroRepoBasic { static protected LiteDB.LiteDatabase d_writer = null;

    public string ConnectionString { get; set; }

    public HoroRepoBasic(string CStr)
    {
        ConnectionString = CStr;
        if (d_writer == null)
            d_writer = new LiteDB.LiteDatabase(CStr);
    }
}

}

public class HoroRepo : HoroRepoBasic { static string CName = "HoroItem";

    public LiteDB.ILiteCollection<HoroItem> Collection { get { return d_writer.GetCollection<HoroItem>(CName); } }

    public HoroRepo(string CStr) : base(CStr) { }

    public IEnumerable<HoroItem> FindAll()
    {
        return Collection.FindAll();
    }

    public HoroItem Find(int id)
    {
        return Collection.FindOne(v => v.Id == id);
    }

    public IEnumerable<HoroItem> FindByUser(User u)
    {
        return Collection.Find(v => v.user.Id == u.Id);
    }

    #region CRUD
    public void Insert(HoroItem u)
    {
        Collection.Insert(u);
    }

    public void Insert(IEnumerable<HoroItem> us)
    {
        Collection.InsertBulk(us);
    }

//*****

qart2003 commented 4 years ago

Hello @lbnascimento, my website is dad from time to time and I can get error. But I can see what after error when I need to restart site. In App I created singleton ArticleService which use ArticleDataMapper and even Article.db has just the one collection. What do I wrong? Ram is enough on server, free space too. Just 1.5k users/day - not pop site. (5.05 version, not 5.07)

From Global The process cannot access the file 'C:\inetpub\wwwroot\qj\App_Data\articles.db' because it is being used by another process. at System.IO.Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) at LiteDB.Engine.FileStreamFactory.GetStream(Boolean canWrite, Boolean sequencial) at LiteDB.Engine.StreamPool.<>c__DisplayClass3_0.<.ctor>b0() at System.Lazy1.CreateValue() at System.Lazy1.LazyInitValue() at LiteDB.Engine.StreamPool.get_Writer() at LiteDB.Engine.DiskService..ctor(EngineSettings settings, Int32[] memorySegmentSizes) at LiteDB.Engine.LiteEngine..ctor(EngineSettings settings) at LiteDB.ConnectionString.CreateEngine() at LiteDB.LiteDatabase..ctor(ConnectionString connectionString, BsonMapper mapper) at LiteDB.LiteDatabase..ctor(String connectionString, BsonMapper mapper) at JApp.DAL.Articles.BasicArticlesDataMapper..ctor(String CStr) at JApp.DAL.Articles.ArticleDataMapper..ctor(String CStr) at JApp.SL.Articles.ArticlesServiceBase.get_ArticleDataMapper() at JApp.SL.Articles.ArticleService.FindAll() at JApp.SL.Articles.ArticleServiceLite.Init() at JApp.SL.Articles.ArticleServiceLite..ctor(ArticleService articleService) at JApp.UI.VarStore.InitVars() in C:\inetpub\wwwroot\qj\App_Code\varstore.cs:line 405 at ASP.global_asax.Application_Start(Object sender, EventArgs e) in C:\inetpub\wwwroot\qj\global.asax:line 10

lbnascimento commented 4 years ago

@qart2003 Are you by any chance accessing the same datafile from different processes? If that is the case, you must use Shared mode.

Are you using an Azure web app? We've had similar issues with Azure recently, but I haven't been able to reproduce them.

qart2003 commented 4 years ago

@lbnascimento , I dont use azure or different processes and have the one server. In UI App (JApp.UI) I created singleton ArticleService (JApp.SL.dll) which use ArticleDataMapper (JApp.DAL.dll) and even Article.db has just the one collection. Add info: static protected LiteDB.LiteDatabase d_writer = null; And in constructor: ConnectionString = CStr; if (d_writer == null) d_writer = new LiteDB.LiteDatabase(CStr); It means I cant create more then one LiteDB.LiteDatabase object per file with database What do I wrong? Add info: Articles.db is more active data for my users Probably it means some problem with multithread access? (its website and every request is a single thread) May be error in optimized multithread algorythms I have not very pop site and not more 300 users (highest level, ussualy very less) per hour but may be with invisible google bots value is higher (I dont know)

lbnascimento commented 4 years ago

@qart2003 It's possible the server process is being closes without properly disposing the LiteDatabase. Try add a using block or, if not possible, adding a finally block that calls LiteDatabase.Dispose().

Also, it's possible that some external process, like an anti-virus, is locking the file (one user reported that TortoiseGit was locking his datafile).

qart2003 commented 4 years ago

I cant do dispose, I handly copy site to server, server has not antivirus or any other external process, exclude probably I dont know about hosting provider processes which it runs on my vps. I will try to find desision