/// <summary> /// Reloads the users. /// </summary> /// <param name="o">O.</param> /// <param name="e">E.</param> public static void ReloadUsers(object o, EventArgs e) { if (!File.Exists(Configuration.UserDB)) { DebugLog("There is no user db to load users from"); return; } DebugLog("Reloading users"); List<string> lines = new List<string>(); lines.AddRange(File.ReadAllLines(Configuration.UserDB)); lock (GlobalCaches) { List<User> remove = new List<User>(); foreach (User user in GlobalCaches.Keys) { if (user.username != ":global") { remove.Add(user); } } foreach (string user in lines) { if (user.Contains (":")) { string name = user.Substring(0, user.IndexOf (":")); string pw = user.Substring(user.IndexOf (":") + 1); User xx = getUser(name); if (xx == null) { xx = new User(name); xx.password = pw; GlobalCaches.Add (xx, new Cache()); DebugLog("Created cache: " + name); } else { remove.Remove(xx); } } else { DebugLog("Invalid record: " + user); } } foreach (User c in remove) { DebugLog("Removing: " + c.username); GlobalCaches.Remove(c); } } }
/// <summary> /// Loads the users. /// </summary> public static void LoadUsers() { watcher = new FileSystemWatcher(); watcher.Path = Configuration.Path; string filename = Configuration.UserDB; if (filename.Contains (Path.DirectorySeparatorChar.ToString())) { filename = filename.Substring (filename.LastIndexOf(Path.DirectorySeparatorChar.ToString()) +1 ); } watcher.Filter = filename; watcher.Changed += new FileSystemEventHandler(ReloadUsers); watcher.Created += new FileSystemEventHandler(ReloadUsers); watcher.EnableRaisingEvents = true; if (!File.Exists(Configuration.UserDB)) { DebugLog("There is no user db to load users from"); return; } List<string> lines = new List<string>(); lines.AddRange(File.ReadAllLines(Configuration.UserDB)); lock (GlobalCaches) { foreach (string i in lines) { if (i.Contains (":")) { string name = i.Substring(0, i.IndexOf (":")); string pw = i.Substring(i.IndexOf (":") + 1); User user = new User(name); user.password = pw; GlobalCaches.Add (user, new Cache()); DebugLog("User: "******"Invalid record: " + i); } } } }
/// <summary> /// The entry point of the program, where the program control starts and ends. /// </summary> /// <param name="args">The command-line arguments.</param> public static void Main(string[] args) { Configuration.Path = Directory.GetCurrentDirectory(); if (!Terminal.Parse (args)) { Log ("Starting sharp memcached server version " + Configuration.Version); st = DateTime.Now; if (Configuration.Verbosity > 0) { DebugLog ("Verbosity: " + Configuration.Verbosity.ToString()); } if (!Configuration.UDP && !Configuration.TCP) { Log ("ERROR: you must enable either tcp or udp"); return; } Configuration.InstanceMemoryLimitByteSize = (ulong)Configuration.InstanceMemoryLimit * 1024 * 1024; Configuration.GlobalMemoryLimitByteSize = (ulong)Configuration.GlobalMemoryLimit * 1024 * 1024; Thread cleaner = new Thread(GC); cleaner.Start(); // we have 1 shared cache for everyone GlobalUser = new User(":global"); GlobalCaches.Add (GlobalUser, new Cache()); LoadUsers(); // create a new thread for tcp and start it Thread tcp = new Thread(Memcache.ListenTCP); tcp.Name = "tcp listener"; tcp.Start(); Thread udp = new Thread(Memcache.ListenUDP); udp.Name = "udp listener"; udp.Start(); while (isRunning) { Thread.Sleep(100); } } }
private static void Stats(string parameters, ref System.IO.StreamWriter w, User user) { if (parameters == "") { Cache cache; lock (MainClass.GlobalCaches) { cache = MainClass.GlobalCaches[user]; } Send ("STAT pid " + System.Diagnostics.Process.GetCurrentProcess ().Id.ToString (), ref w); Send ("STAT uptime " + MainClass.uptime ().ToString (), ref w); Send ("STAT time " + ToUnix().ToString(), ref w); Send ("STAT version sharp-memcached" + Configuration.Version, ref w); Send ("STAT pointer_size " + (IntPtr.Size * 8).ToString(), ref w); Send ("STAT global_memory_limit " + Configuration.GlobalMemoryLimitByteSize.ToString(), ref w); Send ("STAT user_memory_limit " + Configuration.InstanceMemoryLimitByteSize.ToString(), ref w); Send ("STAT hash_bytes_local " + cache.Size.ToString(), ref w); Send ("STAT user " + user.username, ref w); Send ("STAT hash_bytes " + Cache.GlobalSize.ToString(), ref w); Send ("STAT hashtables " + MainClass.GlobalCaches.Count.ToString (), ref w); Send ("STAT curr_items " + cache.Count().ToString(), ref w); Send ("STAT total_connections " + MainClass.Connections.ToString (), ref w); Send ("STAT curr_connections " + MainClass.OpenConnections.ToString (), ref w); Send ("STAT cmd_get " + cache.cmd_get.ToString(), ref w); Send ("STAT cmd_set " + cache.cmd_set.ToString (), ref w); Send ("STAT cmd_flush " + cache.cmd_flush.ToString(), ref w); Send ("STAT cmd_touch " + cache.cmd_touch.ToString(), ref w); Send ("STAT get_hits " + cache.get_hits.ToString(), ref w); Send ("STAT get_misses " + cache.get_misses.ToString(), ref w); Send ("STAT delete_misses " + cache.delete_misses.ToString(), ref w); Send ("STAT delete_hits " + cache.delete_hits.ToString(), ref w); Send ("STAT incr_misses " + cache.incr_misses.ToString(), ref w); Send ("STAT incr_hits " + cache.incr_hits.ToString(), ref w); Send ("STAT decr_misses " + cache.decr_misses.ToString(), ref w); Send ("STAT decr_hits " + cache.decr_hits.ToString(), ref w); Send ("STAT cas_hits " + cache.cas_hits.ToString(), ref w); Send ("STAT cas_misses " + cache.cas_misses.ToString(), ref w); return; } }
private static void TouchData(string parameters, ref System.IO.StreamWriter Writer, User user) { string key = null; int exptime = 0; //<command name> <key> <flags> <exptime> <bytes> string[] part; part = parameters.Split(' '); if (part.Length < 2) { // invalid format SendError(ErrorCode.MissingValues, ref Writer); return; } key = part[0]; if (!int.TryParse (part[1], out exptime)) { SendError(ErrorCode.MissingValues, ref Writer); return; } lock(MainClass.GlobalCaches) { if (!MainClass.GlobalCaches.ContainsKey(user)) { // this should never happen MainClass.DebugLog("There is no cache for user " + user.username); SendError(ErrorCode.InternalError, ref Writer); return; } if (MainClass.GlobalCaches[user].Touch (key, exptime)) { if (!parameters.EndsWith ("noreply")) { Send ("TOUCHED", ref Writer); } } else { if (!parameters.EndsWith ("noreply")) { Send("NOT_FOUND", ref Writer); } } } }
/// <summary> /// Set the specified parameters, r and w. /// </summary> /// <param name="parameters">Parameters.</param> /// <param name="r">The red component.</param> /// <param name="w">The width.</param> private static int Set(string parameters, ref System.IO.StreamReader r, ref System.IO.StreamWriter w, User user) { string key = null; int flags = 0; int exptime = 0; int size = 0; //<command name> <key> <flags> <exptime> <bytes> string[] part = null; part = parameters.Split(' '); if (part.Length < 4) { // invalid format SendError (ErrorCode.MissingValues, ref w); return 1; } key = part[0]; if (!int.TryParse (part[1], out flags)) { SendError (ErrorCode.InvalidValues, ref w); return 1; } if (!int.TryParse (part[2], out exptime)) { SendError (ErrorCode.InvalidValues, ref w); return 1; } if (!int.TryParse (part[3], out size)) { SendError (ErrorCode.InvalidValues, ref w); return 1; } if (size < 0) { SendError (ErrorCode.InvalidValues, ref w); return 1; } if ((ulong)size > Configuration.InstanceMemoryLimitByteSize) { SendError (ErrorCode.OutOfMemory, ref w); return 3; } // everything is ok let's go string chunk = r.ReadLine(); while (chunk.Length < size) { chunk += "\n" + r.ReadLine(); } if (chunk.Length > size) { // too big SendError (ErrorCode.InvalidValues, ref w); return 4; } Cache.Item Item = new Cache.Item(chunk, exptime, flags); lock (MainClass.GlobalCaches) { if (FreeSize (MainClass.GlobalCaches[user]) < Item.getSize ()) { // we don't have enough free size let's try to free some if (!MainClass.GlobalCaches[user].FreeSpace(Item.getSize ())) { // error SendError (ErrorCode.OutOfMemory, ref w); return 1; } } MainClass.GlobalCaches[user].Set (key, Item); } if (!parameters.EndsWith ("noreply")) { Send ("STORED", ref w); } // unknown error return 0; }
private static void Prepend(string pars, ref System.IO.StreamWriter w, ref System.IO.StreamReader r, User user) { if (!pars.Contains (" ")) { SendError (ErrorCode.InvalidValues, ref w); return; } string[] part = pars.Split (' '); if (part.Length < 4) { SendError (ErrorCode.MissingValues, ref w); return; } string key = part[0]; int flags = 0; int exptime = 0; int size = 0; //<command name> <key> <flags> <exptime> <bytes> if (!int.TryParse (part[1], out flags)) { SendError (ErrorCode.InvalidValues, ref w); return; } if (!int.TryParse (part[2], out exptime)) { SendError (ErrorCode.InvalidValues, ref w); return; } if (!int.TryParse (part[3], out size)) { SendError (ErrorCode.InvalidValues, ref w); return; } if (size < 0) { SendError (ErrorCode.InvalidValues, ref w); return; } if ((ulong)size > Configuration.InstanceMemoryLimitByteSize) { // error SendError (ErrorCode.OutOfMemory, ref w); return; } // everything is ok let's go string chunk = r.ReadLine(); while (chunk.Length < size) { chunk += "\n" + r.ReadLine(); } if (chunk.Length > size) { // too big SendError (ErrorCode.InvalidValues, ref w); return; } Cache cache = MainClass.GlobalCaches[user]; Cache.Item item = cache.Get (key, true); if (item == null) { Send ("NOT_FOUND", ref w); return; } Cache.Item replacement = new Cache.Item(item.value + chunk, item.expiry, item.flags); if (FreeSize (cache) < replacement.getSize()) { // we don't have enough free size let's try to free some if (!cache.FreeSpace(replacement.getSize())) { // error SendError (ErrorCode.OutOfMemory, ref w); return; } } cache.hardSet (key, replacement); if (!pars.EndsWith("noreply")) { Send ("STORED", ref w); } }
private static void increment(string pars, ref System.IO.StreamWriter w, ref System.IO.StreamReader r, User user) { if (!pars.Contains (" ")) { SendError (ErrorCode.InvalidValues, ref w); return; } string[] values = pars.Split (' '); if (values.Length < 2) { SendError (ErrorCode.MissingValues, ref w); return; } string key = values[0]; int jump; if (!int.TryParse (values[1], out jump)) { SendError(ErrorCode.InvalidValues, ref w); return; } Cache cache = MainClass.GlobalCaches[user]; Cache.Item item = cache.Get (key, true); if (item == null) { Send ("NOT_FOUND", ref w); cache.incr_misses++; return; } int current; if (!int.TryParse (item.value, out current)) { SendError (ErrorCode.InvalidValues, ref w); return; } current += jump; cache.incr_hits++; cache.hardSet (key, new Cache.Item(current.ToString (), item.expiry, item.flags)); Send (current.ToString (), ref w); }
private static void Gets(string pars, ref System.IO.StreamWriter w, ref System.IO.StreamReader r, User user) { string[] items = null; if (pars.Contains (" ")) { items = pars.Split (' '); } else { items = new string[] {pars}; } Cache cache = null; lock(MainClass.GlobalCaches) { if (!MainClass.GlobalCaches.ContainsKey(user)) { SendError (ErrorCode.InternalError, ref w); return; } cache = MainClass.GlobalCaches[user]; } string data = ""; foreach (string curr in items) { Cache.Item item = cache.Get (curr); if (item != null) { data += "VALUE " + curr + " " + item.flags.ToString() + " " + item.value.Length.ToString() + " " + item.cas.ToString() + "\r\n" + item.value + "\r\n"; } } Send(data + "END", ref w); }
private static void Delete(string pars, ref System.IO.StreamWriter w, ref System.IO.StreamReader r, User user) { string key = pars; if (key.Contains (" ")) { key = key.Substring(0, key.IndexOf(" ")); } Cache cache = null; lock(MainClass.GlobalCaches) { if (!MainClass.GlobalCaches.ContainsKey(user)) { SendError (ErrorCode.InternalError, ref w); return; } cache = MainClass.GlobalCaches[user]; } if (cache.Delete(key)) { if (!pars.EndsWith ("noreply")) { Send ("DELETED", ref w); } return; } if (!pars.EndsWith ("noreply")) { Send ("NOT_FOUND", ref w); } }