static Inotify() { if (Environment.GetEnvironmentVariable("BEAGLE_DISABLE_INOTIFY") != null) { Logger.Log.Debug("BEAGLE_DISABLE_INOTIFY is set"); return; } if (Environment.GetEnvironmentVariable("BEAGLE_INOTIFY_VERBOSE") != null) { Inotify.Verbose = true; } try { inotify_fd = inotify_glue_init(); } catch (EntryPointNotFoundException) { Logger.Log.Info("Inotify not available on system."); return; } if (inotify_fd < 0) { Mono.Unix.Native.Errno errno = Mono.Unix.Native.NativeConvert.ToErrno(-inotify_fd); string error_message; if (errno == Mono.Unix.Native.Errno.ENOSYS) { error_message = "Inotify not supported! You need a 2.6.13 kernel or later with CONFIG_INOTIFY enabled."; } else { error_message = Mono.Unix.UnixMarshal.GetErrorDescription(errno); } Logger.Log.Warn("Could not initialize inotify: {0}", error_message); } else { try { FileStream fs = new FileStream("/proc/sys/fs/inotify/max_user_watches", FileMode.Open, FileAccess.Read); StreamReader r = new StreamReader(fs); string line = r.ReadLine(); r.Close(); int watches = -1; try { watches = Int32.Parse(line); } catch (FormatException) { } if (watches > -1 && watches < 32768) { Log.Warn("Inotify watches may be too low ({0}) for some users! Increase it to at least 65535 by setting fs.inotify.max_user_watches in /etc/sysctl.conf", watches); } } catch { } } }
// Ensure our watch exists, meets all the subscribers requirements, // and isn't matching any other events that we don't care about. private static void CreateOrModifyWatch(WatchInfo watched) { EventType new_mask = base_mask; foreach (WatchInternal watch in watched.Subscribers) { new_mask |= watch.Mask; } if (watched.Wd >= 0 && watched.Mask == new_mask) { return; } //Log.Debug ("{0} inotify watch on {1}", watched.Wd >= 0 ? "Recreating" : "Creating", watched.Path); // We rely on the behaviour that watching the same inode twice won't result // in the wd value changing. // (no need to worry about watched_by_wd being polluted with stale watches) int wd = -1; wd = inotify_glue_watch(inotify_fd, watched.Path, new_mask); if (wd < 0) { Mono.Unix.Native.Errno errno = Mono.Unix.Native.NativeConvert.ToErrno(-wd); if (!watch_limit_error_displayed && errno == Mono.Unix.Native.Errno.ENOSPC) { Log.Error("Maximum inotify watch limit hit adding watch to {0}. Try adjusting /proc/sys/fs/inotify/max_user_watches", watched.Path); watch_limit_error_displayed = true; } string msg = String.Format("Attempt to watch {0} failed: {1}", watched.Path, Mono.Unix.UnixMarshal.GetErrorDescription(errno)); throw new IOException(msg); } if (watched.Wd >= 0 && watched.Wd != wd) { string msg = String.Format("Watch handle changed unexpectedly!", watched.Path); throw new IOException(msg); } watched.Wd = wd; watched.Mask = new_mask; }
private static void Unsubscribe(WatchInfo watched, WatchInternal watch) { watched.Subscribers.Remove(watch); // Other subscribers might still be around if (watched.Subscribers.Count > 0) { // Minimize it CreateOrModifyWatch(watched); return; } int retval = inotify_glue_ignore(inotify_fd, watched.Wd); if (retval < 0) { Mono.Unix.Native.Errno errno = Mono.Unix.Native.NativeConvert.ToErrno(-retval); string msg = String.Format("Attempt to ignore {0} failed: {1}", watched.Path, Mono.Unix.UnixMarshal.GetErrorDescription(errno)); throw new IOException(msg); } Forget(watched); return; }
public override bool Obtain() { Log("Trying to obtain lock " + lockFile.FullName); if (Lucene.Net.Store.FSDirectory.disableLocks || Enclosing_Instance.InstanceDisableLock) { return(true); } bool tmpBool; if (System.IO.File.Exists(Enclosing_Instance.lockDir.FullName)) { tmpBool = true; } else { tmpBool = System.IO.Directory.Exists(Enclosing_Instance.lockDir.FullName); } if (!tmpBool) { try { System.IO.Directory.CreateDirectory(Enclosing_Instance.lockDir.FullName); } catch (Exception) { throw new System.IO.IOException("Cannot create lock directory: " + Enclosing_Instance.lockDir); } } try { int fd = Mono.Unix.Native.Syscall.open( lockFile.FullName, Mono.Unix.Native.OpenFlags.O_RDWR | Mono.Unix.Native.OpenFlags.O_CREAT | Mono.Unix.Native.OpenFlags.O_EXCL, Mono.Unix.Native.FilePermissions.S_IRUSR); if (fd == -1) { Mono.Unix.Native.Errno error = Mono.Unix.Native.Stdlib.GetLastError(); if (error == Mono.Unix.Native.Errno.ENOSPC) { throw new Beagle.Util.NoSpaceException(); } else { throw new System.IO.IOException("Could not create lock file: " + Mono.Unix.Native.Stdlib.strerror(error)); } } // This code replaces the commented-out code below because // it ends up being much faster. The reason for this is // that closing a UnixStream causes Syscall.fsync() to be // called, and that apparently is extremely slow! // // Time(ms) Count P/call(ms) Method name // 1563.926 68 22.999 Mono.Unix.Native.Syscall::fsync(int) // // Since the lock file is written out very often, this time // adds up and noticably slows down indexing. IntPtr ptr = IntPtr.Zero; long ret; try { string s = System.Diagnostics.Process.GetCurrentProcess().Id.ToString() + "\n"; ptr = Mono.Unix.UnixMarshal.StringToHeap(s); do { ret = Mono.Unix.Native.Syscall.write(fd, ptr, (ulong)s.Length); } while (Mono.Unix.UnixMarshal.ShouldRetrySyscall((int)ret)); if ((int)ret == -1) { Mono.Unix.Native.Errno error = Mono.Unix.Native.Stdlib.GetLastError(); if (error == Mono.Unix.Native.Errno.ENOSPC) { throw new Beagle.Util.NoSpaceException(); } else { Mono.Unix.UnixMarshal.ThrowExceptionForError(error); } } } finally { Mono.Unix.UnixMarshal.FreeHeap(ptr); do { ret = Mono.Unix.Native.Syscall.close(fd); } while (Mono.Unix.UnixMarshal.ShouldRetrySyscall((int)ret)); Mono.Unix.UnixMarshal.ThrowExceptionForLastErrorIf((int)ret); } //System.IO.StreamWriter w = new System.IO.StreamWriter (new Mono.Unix.UnixStream (fd, true)); //w.WriteLine (System.Diagnostics.Process.GetCurrentProcess ().Id); //w.Close (); return(true); } catch (Beagle.Util.NoSpaceException e) { throw e; } catch (Exception e) { Log("Exception in CreateNew for file:" + lockFile.FullName + ":" + e); return(false); } }