Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Caching folder structure in database

  • Loading branch information...
commit c04677394e650b079cc982be938b91791fd848d2 1 parent 2c7d719
@a-fung authored
View
94 source/aspnetserver/Collection.cs
@@ -5,6 +5,7 @@
using System.Text;
using System.Web;
using afung.MangaWeb3.Common;
+using Newtonsoft.Json;
namespace afung.MangaWeb3.Server
{
@@ -40,6 +41,32 @@ public bool AutoAdd
private set;
}
+ public int CacheStatus
+ {
+ get;
+ private set;
+ }
+
+ private string _folderCache;
+
+ public string FolderCache
+ {
+ get
+ {
+ if (CacheStatus == 0)
+ {
+ if (_folderCache == null)
+ {
+ _folderCache = Convert.ToString(Database.Select("foldercache", "`id`='" + Id + "'")[0]["content"]);
+ }
+
+ return _folderCache;
+ }
+
+ return null;
+ }
+ }
+
private static Dictionary<int, Collection> cache = new Dictionary<int, Collection>();
private Collection()
@@ -54,6 +81,7 @@ public static Collection CreateNewCollection(string name, string path, bool publ
newCollection.Path = path;
newCollection.Public = public_;
newCollection.AutoAdd = autoadd;
+ newCollection.CacheStatus = 1;
return newCollection;
}
@@ -72,6 +100,7 @@ private static Collection FromData(Dictionary<string, object> data)
collection.Path = Convert.ToString(data["path"]);
collection.Public = Convert.ToInt32(data["public"]) == 1;
collection.AutoAdd = Convert.ToInt32(data["autoadd"]) == 1;
+ collection.CacheStatus = Convert.ToInt32(data["cachestatus"]);
cache[collection.Id] = collection;
return collection;
@@ -206,6 +235,7 @@ public void Save()
data.Add("path", Path);
data.Add("public", Public ? 1 : 0);
data.Add("autoadd", AutoAdd ? 1 : 0);
+ data.Add("cachestatus", CacheStatus);
if (Id == -1)
{
@@ -244,9 +274,9 @@ public static CollectionJson[] ToJsonArray(Collection[] collections)
public static void DeleteCollections(int[] ids)
{
+ Manga.DeleteMangasFromCollectionIds(ids);
Database.Delete("collection", Database.BuildWhereClauseOr("id", ids));
Database.Delete("collectionuser", Database.BuildWhereClauseOr("cid", ids));
- Manga.DeleteMangasFromCollectionIds(ids);
}
public static void SetCollectionsPublic(int[] ids, bool public_)
@@ -276,5 +306,67 @@ public bool Accessible(AjaxBase ajax)
return Database.Select("collection", where, null, null, "`id`").Length > 0;
}
+
+ public void MarkFolderCacheDirty()
+ {
+ CacheStatus = 1;
+ Save();
+ }
+
+ public void ProcessFolderCache()
+ {
+ if (CacheStatus == 0 || CacheStatus == 2)
+ {
+ return;
+ }
+
+ CacheStatus = 2;
+ Save();
+
+ FolderJson folder = new FolderJson();
+ folder.name = Name;
+ folder.subfolders = new FolderJson[] { };
+ int collectionPathLength = Path.Length;
+ string separator = "\\";
+
+ Dictionary<string, FolderJson> folderDictionary = new Dictionary<string, FolderJson>();
+ Dictionary<string, object>[] resultSet = Database.Select("manga", "`cid`=" + Database.Quote(Id.ToString()), null, null, "`path`");
+ folderDictionary[""] = folder;
+
+ foreach (Dictionary<string, object> result in resultSet)
+ {
+ string path = Convert.ToString(result["path"]).Substring(collectionPathLength);
+ int i = 0, j = 0;
+
+ while ((i = path.IndexOf(separator, j)) != -1)
+ {
+ string relativePath = path.Substring(0, i);
+ if (!folderDictionary.ContainsKey(relativePath.ToLowerInvariant()))
+ {
+ FolderJson subfolder = new FolderJson();
+ subfolder.name = path.Substring(j, i - j);
+ subfolder.subfolders = new FolderJson[] { };
+ folderDictionary[relativePath.ToLowerInvariant()] = subfolder;
+
+ int k;
+ FolderJson parentFolder = folderDictionary[(k = relativePath.LastIndexOf(separator)) == -1 ? "" : relativePath.Substring(0, k).ToLowerInvariant()];
+ FolderJson[] newSubfolders = new FolderJson[parentFolder.subfolders.Length + 1];
+ Array.Copy(parentFolder.subfolders, newSubfolders, parentFolder.subfolders.Length);
+ newSubfolders[parentFolder.subfolders.Length] = subfolder;
+ parentFolder.subfolders = newSubfolders;
+ }
+
+ j = i + 1;
+ }
+ }
+
+ Dictionary<string, object> cacheData = new Dictionary<string, object>();
+ cacheData.Add("id", Id);
+ cacheData.Add("content", _folderCache = JsonConvert.SerializeObject(folder));
+ Database.Replace("foldercache", cacheData);
+
+ CacheStatus = 0;
+ Save();
+ }
}
}
View
1  source/aspnetserver/Handler/AdminCollectionEditNameRequestHandler.cs
@@ -53,6 +53,7 @@ public override void HandleRequest(string jsonString, AjaxBase ajax)
{
response.status = 0;
collection.Name = request.name;
+ collection.MarkFolderCacheDirty();
collection.Save();
}
}
View
1  source/aspnetserver/Handler/AdminMangaAddRequestHandler.cs
@@ -48,6 +48,7 @@ public override void HandleRequest(string jsonString, AjaxBase ajax)
{
response.status = 0;
Manga.CreateNewManga(collection, request.path).Save();
+ collection.MarkFolderCacheDirty();
}
ajax.ReturnJson(response);
View
53 source/aspnetserver/Handler/FolderRequestHandler.cs
@@ -18,49 +18,36 @@ public override void HandleRequest(string jsonString, AjaxBase ajax)
FolderResponse response = new FolderResponse();
Collection[] collections = Collection.GetAccessible(ajax);
List<FolderJson> folders = new List<FolderJson>();
- string separator = "\\";
+ bool ready = true;
foreach (Collection collection in collections)
{
- FolderJson folder = new FolderJson();
- folder.name = collection.Name;
- folder.subfolders = new FolderJson[] { };
- folders.Add(folder);
- int collectionPathLength = collection.Path.Length;
-
- Dictionary<string, FolderJson> folderDictionary = new Dictionary<string, FolderJson>();
- Dictionary<string, object>[] resultSet = Database.Select("manga", "`cid`=" + Database.Quote(collection.Id.ToString()), null, null, "`path`");
- folderDictionary[""] = folder;
-
- foreach (Dictionary<string, object> result in resultSet)
+ string folderJsonString = collection.FolderCache;
+ if (folderJsonString != null)
+ {
+ folders.Add(Utility.ParseJson<FolderJson>(folderJsonString));
+ }
+ else
{
- string path = Convert.ToString(result["path"]).Substring(collectionPathLength);
- int i = 0, j = 0;
+ ready = false;
- while ((i = path.IndexOf(separator, j)) != -1)
+ if (collection.CacheStatus == 1)
{
- string relativePath = path.Substring(0, i);
- if (!folderDictionary.ContainsKey(relativePath.ToLowerInvariant()))
- {
- FolderJson subfolder = new FolderJson();
- subfolder.name = path.Substring(j, i - j);
- subfolder.subfolders = new FolderJson[] { };
- folderDictionary[relativePath.ToLowerInvariant()] = subfolder;
-
- int k;
- FolderJson parentFolder = folderDictionary[(k = relativePath.LastIndexOf(separator)) == -1 ? "" : relativePath.Substring(0, k).ToLowerInvariant()];
- FolderJson[] newSubfolders = new FolderJson[parentFolder.subfolders.Length + 1];
- Array.Copy(parentFolder.subfolders, newSubfolders, parentFolder.subfolders.Length);
- newSubfolders[parentFolder.subfolders.Length] = subfolder;
- parentFolder.subfolders = newSubfolders;
- }
-
- j = i + 1;
+ ThreadHelper.Run("CollectionProcessFolderCache", collection.Id);
}
}
}
- response.folders = folders.ToArray();
+ if (!ready)
+ {
+ response.status = 1;
+ }
+ else
+ {
+ response.status = 0;
+ response.folders = folders.ToArray();
+ }
+
ajax.ReturnJson(response);
}
}
View
2  source/aspnetserver/Manga.cs
@@ -465,6 +465,7 @@ public void ChangePath(string newPath, int newType)
InnerRefreshContent();
Status = 0;
Save();
+ ParentCollection.MarkFolderCacheDirty();
}
public void Save()
@@ -581,6 +582,7 @@ public void Delete()
UpdateTags(new string[0]);
Database.Delete("manga", "`id`=" + Database.Quote(Id.ToString()));
Database.Delete("meta", "`mid`=" + Database.Quote(Id.ToString()));
+ ParentCollection.MarkFolderCacheDirty();
}
public static string[] GetAllTags()
View
15 source/aspnetserver/ThreadHelper.cs
@@ -47,6 +47,9 @@ public static void InnerRun(object data)
case "ProcessAutoAddStage2":
ProcessAutoAddStage2(parameters);
break;
+ case "CollectionProcessFolderCache":
+ CollectionProcessFolderCache(parameters);
+ break;
default:
return;
}
@@ -189,6 +192,7 @@ private static void ProcessAutoAddStage2(object[] parameters)
if (path.IndexOf(collection.Path, StringComparison.InvariantCultureIgnoreCase) == 0 && Manga.CheckMangaType(path) != -1)
{
Manga.CreateNewManga(collection, path).Save();
+ collection.MarkFolderCacheDirty();
}
}
}
@@ -199,5 +203,16 @@ private static void ProcessAutoAddStage2(object[] parameters)
ThreadHelper.Run("ProcessAutoAddStage2", files, index + 1);
}
+
+ private static void CollectionProcessFolderCache(object[] parameters)
+ {
+ int id = (int)parameters[0];
+ Collection collection = Collection.GetById(id);
+
+ if (collection != null)
+ {
+ collection.ProcessFolderCache();
+ }
+ }
}
}
View
8 source/aspnetserver/install.sql
@@ -5,11 +5,19 @@ CREATE TABLE `collection` (
`public` tinyint(1) NOT NULL,
`path` varchar(330) NOT NULL,
`autoadd` tinyint(1) NOT NULL,
+ `cachestatus` tinyint(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `public` (`public`),
KEY `autoadd` (`autoadd`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `foldercache`;
+CREATE TABLE `foldercache` (
+ `id` int(11) NOT NULL,
+ `content` longtext NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
DROP TABLE IF EXISTS `collectionuser`;
CREATE TABLE `collectionuser` (
`cid` int(11) NOT NULL,
View
1  source/csharpcommon/FolderResponse.cs
@@ -8,6 +8,7 @@ namespace afung.MangaWeb3.Common
{
public class FolderResponse : JsonResponse
{
+ public int status;
public FolderJson[] folders;
}
}
View
1  source/haxe/afung/mangaWeb3/common/FolderResponse.hx
@@ -7,5 +7,6 @@ package afung.mangaWeb3.common;
class FolderResponse extends JsonResponse
{
+ public var status:Int;
public var folders:Array<FolderJson>;
}
View
87 source/haxe/afung/mangaWeb3/server/Collection.hx
@@ -1,6 +1,8 @@
package afung.mangaWeb3.server;
import afung.mangaWeb3.common.CollectionJson;
+import afung.mangaWeb3.common.FolderJson;
+import haxe.Json;
import php.FileSystem;
/**
@@ -20,6 +22,27 @@ class Collection
public var AutoAdd(default, null):Bool;
+ public var CacheStatus(default, null):Int;
+
+ private var _folderCache:String;
+
+ public var FolderCache(get_FolderCache, never):String;
+
+ private function get_FolderCache():String
+ {
+ if (CacheStatus == 0)
+ {
+ if (_folderCache == null)
+ {
+ _folderCache = Std.string(Database.Select("foldercache", "`id`='" + Id + "'")[0].get("content"));
+ }
+
+ return _folderCache;
+ }
+
+ return null;
+ }
+
private static var cache:IntHash<Collection> = new IntHash<Collection>();
private function new()
@@ -34,6 +57,7 @@ class Collection
newCollection.Path = path;
newCollection.Public = public_;
newCollection.AutoAdd = autoadd;
+ newCollection.CacheStatus = 1;
return newCollection;
}
@@ -52,6 +76,7 @@ class Collection
collection.Path = Std.string(data.get("path"));
collection.Public = Std.parseInt(data.get("public")) == 1;
collection.AutoAdd = Std.parseInt(data.get("autoadd")) == 1;
+ collection.CacheStatus = Std.parseInt(data.get("cachestatus"));
cache.set(collection.Id, collection);
return collection;
@@ -184,6 +209,7 @@ class Collection
data.set("path", Path);
data.set("public", Public ? 1 : 0);
data.set("autoadd", AutoAdd ? 1 : 0);
+ data.set("cachestatus", CacheStatus);
if (Id == -1)
{
@@ -222,9 +248,9 @@ class Collection
public static function DeleteCollections(ids:Array<Int>):Void
{
+ Manga.DeleteMangasFromCollectionIds(ids);
Database.Delete("collection", Database.BuildWhereClauseOr("id", ids));
Database.Delete("collectionuser", Database.BuildWhereClauseOr("cid", ids));
- Manga.DeleteMangasFromCollectionIds(ids);
}
public static function SetCollectionsPublic(ids:Array<Int>, public_:Bool):Void
@@ -254,4 +280,63 @@ class Collection
return Database.Select("collection", where, null, null, "`id`").length > 0;
}
+
+ public function MarkFolderCacheDirty():Void
+ {
+ CacheStatus = 1;
+ Save();
+ }
+
+ public function ProcessFolderCache():Void
+ {
+ if (CacheStatus == 0 || CacheStatus == 2)
+ {
+ return;
+ }
+
+ CacheStatus = 2;
+ Save();
+
+ var folder:FolderJson = new FolderJson();
+ folder.name = Name;
+ folder.subfolders = [];
+ var collectionPathLength:Int = Path.length;
+ var separator:String = "/";
+
+ var folderDictionary:Hash<FolderJson> = new Hash<FolderJson>();
+ var resultSet:Array<Hash<Dynamic>> = Database.Select("manga", "`cid`=" + Database.Quote(Std.string(Id)), null, null, "`path`");
+ folderDictionary.set("", folder);
+
+ for (result in resultSet)
+ {
+ var path:String = Std.string(result.get("path")).substr(collectionPathLength);
+ var i:Int = 0, j:Int = 0;
+
+ while ((i = path.indexOf(separator, j)) != -1)
+ {
+ var relativePath = path.substr(0, i);
+ if (!folderDictionary.exists(relativePath))
+ {
+ var subfolder:FolderJson = new FolderJson();
+ subfolder.name = path.substr(j, i - j);
+ subfolder.subfolders = [];
+ folderDictionary.set(relativePath, subfolder);
+
+ var k:Int;
+ var parentFolder:FolderJson = folderDictionary.get((k = relativePath.lastIndexOf(separator)) == -1 ? "" : relativePath.substr(0, k));
+ parentFolder.subfolders.push(subfolder);
+ }
+
+ j = i + 1;
+ }
+ }
+
+ var cacheData:Hash<Dynamic> = new Hash<Dynamic>();
+ cacheData.set("id", Id);
+ cacheData.set("content", _folderCache = Json.stringify(folder));
+ Database.Replace("foldercache", cacheData);
+
+ CacheStatus = 0;
+ Save();
+ }
}
View
2  source/haxe/afung/mangaWeb3/server/Manga.hx
@@ -433,6 +433,7 @@ class Manga
InnerRefreshContent();
Status = 0;
Save();
+ ParentCollection.MarkFolderCacheDirty();
}
public function Save():Void
@@ -549,6 +550,7 @@ class Manga
UpdateTags([]);
Database.Delete("manga", "`id`=" + Database.Quote(Std.string(Id)));
Database.Delete("meta", "`mid`=" + Database.Quote(Std.string(Id)));
+ ParentCollection.MarkFolderCacheDirty();
}
public static function GetAllTags():Array<String>
View
14 source/haxe/afung/mangaWeb3/server/ThreadHelper.hx
@@ -59,6 +59,8 @@ class ThreadHelper
ProcessAutoAddStage1(parameters);
case "ProcessAutoAddStage2":
ProcessAutoAddStage2(parameters);
+ case "CollectionProcessFolderCache":
+ CollectionProcessFolderCache(parameters);
default:
return;
}
@@ -172,6 +174,7 @@ class ThreadHelper
if (path.indexOf(collection.Path) == 0 && Manga.CheckMangaType(path) != -1)
{
Manga.CreateNewManga(collection, path).Save();
+ collection.MarkFolderCacheDirty();
}
}
}
@@ -195,4 +198,15 @@ class ThreadHelper
ThreadHelper.Run("ProcessAutoAddStage2", [directoriesToRead, currentDirectory, filesInCurrentDirectory]);
}
}
+
+ private static function CollectionProcessFolderCache(parameters:Array<Dynamic>):Void
+ {
+ var id:Int = parameters[0];
+ var collection:Collection = Collection.GetById(id);
+
+ if (collection != null)
+ {
+ collection.ProcessFolderCache();
+ }
+ }
}
View
1  source/haxe/afung/mangaWeb3/server/handler/AdminCollectionEditNameRequestHandler.hx
@@ -57,6 +57,7 @@ class AdminCollectionEditNameRequestHandler extends HandlerBase
{
response.status = 0;
collection.Name = request.name;
+ collection.MarkFolderCacheDirty();
collection.Save();
}
}
View
1  source/haxe/afung/mangaWeb3/server/handler/AdminMangaAddRequestHandler.hx
@@ -52,6 +52,7 @@ class AdminMangaAddRequestHandler extends HandlerBase
{
response.status = 0;
Manga.CreateNewManga(collection, request.path).Save();
+ collection.MarkFolderCacheDirty();
}
ajax.ReturnJson(response);
View
52 source/haxe/afung/mangaWeb3/server/handler/FolderRequestHandler.hx
@@ -4,6 +4,7 @@ import afung.mangaWeb3.common.FolderJson;
import afung.mangaWeb3.common.FolderRequest;
import afung.mangaWeb3.common.FolderResponse;
import afung.mangaWeb3.server.Collection;
+import afung.mangaWeb3.server.Utility;
/**
* ...
@@ -22,44 +23,35 @@ class FolderRequestHandler extends HandlerBase
var response:FolderResponse = new FolderResponse();
var collections:Array<Collection> = Collection.GetAccessible(ajax);
var folders:Array<FolderJson> = new Array<FolderJson>();
- var separator:String = "/";
+ var ready:Bool = true;
for (collection in collections)
{
- var folder:FolderJson = new FolderJson();
- folder.name = collection.Name;
- folder.subfolders = [];
- folders.push(folder);
- var collectionPathLength:Int = collection.Path.length;
-
- var folderDictionary:Hash<FolderJson> = new Hash<FolderJson>();
- var resultSet:Array<Hash<Dynamic>> = Database.Select("manga", "`cid`=" + Database.Quote(Std.string(collection.Id)), null, null, "`path`");
- folderDictionary.set("", folder);
-
- for (result in resultSet)
+ var folderJsonString:String = collection.FolderCache;
+ if (folderJsonString != null)
+ {
+ folders.push(Utility.ParseJson(folderJsonString));
+ }
+ else
{
- var path:String = Std.string(result.get("path")).substr(collectionPathLength);
- var i:Int = 0, j:Int = 0;
-
- while ((i = path.indexOf(separator, j)) != -1)
+ ready = false;
+
+ if (collection.CacheStatus == 1)
{
- var relativePath = path.substr(0, i);
- if (!folderDictionary.exists(relativePath))
- {
- var subfolder:FolderJson = new FolderJson();
- subfolder.name = path.substr(j, i - j);
- subfolder.subfolders = [];
- folderDictionary.set(relativePath, subfolder);
-
- var k:Int;
- var parentFolder:FolderJson = folderDictionary.get((k = relativePath.lastIndexOf(separator)) == -1 ? "" : relativePath.substr(0, k));
- parentFolder.subfolders.push(subfolder);
- }
-
- j = i + 1;
+ ThreadHelper.Run("CollectionProcessFolderCache", [collection.Id]);
}
}
}
+
+ if (!ready)
+ {
+ response.status = 1;
+ }
+ else
+ {
+ response.status = 0;
+ response.folders = folders;
+ }
response.folders = folders;
ajax.ReturnJson(response);
View
23 source/scriptsharp/Module/FoldersModule.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Html;
using System.Runtime.CompilerServices;
using afung.MangaWeb3.Client.Widget;
using afung.MangaWeb3.Common;
@@ -48,13 +49,25 @@ private void AllFoldersButtonClicked(jQueryEvent e)
private extern void FolderRequestSuccess(JsonResponse response);
private void FolderRequestSuccess(FolderResponse response)
{
- jQuery.Select("#folders-area").Children().Remove();
- if (response.folders.Length == 0)
+ if (response.status == 0)
{
- Template.Get("client", "noitem-well", true).AppendTo(jQuery.Select("#folders-area"));
- }
+ jQuery.Select("#folders-area").Children().Remove();
+ if (response.folders.Length == 0)
+ {
+ Template.Get("client", "noitem-well", true).AppendTo(jQuery.Select("#folders-area"));
+ }
- new FoldersWidget(jQuery.Select("#folders-area"), response.folders, "");
+ new FoldersWidget(jQuery.Select("#folders-area"), response.folders, "");
+ }
+ else
+ {
+ Window.SetTimeout(
+ delegate
+ {
+ Request.Send(new FolderRequest(), FolderRequestSuccess);
+ },
+ 1000);
+ }
}
}
}
View
4 source/scriptsharp/Widget/MangaListItem.cs
@@ -351,7 +351,7 @@ private void CoverClicked(jQueryEvent e)
sendingReadReqeust = true;
MangaReadRequest request = new MangaReadRequest();
- request.id = coverRequest.id;
+ request.id = data.id;
request.nextId = nextMangaId;
Request.Send(request, ReadRequestSuccess, ReadRequestFailure);
}
@@ -387,7 +387,7 @@ private static void LoadNextItem()
}
LoadNextItem();
- },
+ },
1000);
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.